"""

    AUTHOR:

        Khushal P Soonderji

    DATE:

        Saturday, 7th Dec., 2024.

    OBJECTIVE:

        To define how auth tokens will be stored in the database.

    REFERENCES:

        N/A

    DOWNLOADS:

        N/A

"""


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                   IMPORT                                                      ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# To make sibling directories accessible for imports:
import sys
sys.path.append(".")
sys.path.append("..")

# For making data behaviour_models:
from pydantic import BaseModel, Field, field_validator, PastDatetime, AwareDatetime
from typing import Optional, Literal, Union

# My utils:
from utils_v2.string import regex
from utils_v2.date_time import date_time

# Other core models:
from models.core.user import CoreUserInfoModel

# To work with MongoDB:
from bson.objectid import ObjectId

# To work with date and time:
import datetime


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                           MACROS / ONE-TIME INIT                                              ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# --- Nothing Yet


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                VARIABLES                                                      ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# --- Nothing Yet


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                  FUNCTIONS                                                    ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


class CoreAuthTokenModel(BaseModel):

    authTokenId: ObjectId = Field(
        description = "the id of the document in mongodb that holds this information; hide from the ui layer",
        frozen = True,
        default = None,
        alias = "_id"
    )

    key: ObjectId = Field(
        description = "the expendable reference to this auth; expose this to the ui",
        frozen = True,
        default_factory = lambda: ObjectId()
    )

    serviceType: Literal["software", "email", "sms", "chat", "paymentGateway"] = Field(
        description = "the kind of service this message was sent/received from",
        frozen = True
    )

    client: Literal[
        "gmail", "outlook",  # ...................... Mail Clients
        "telegram", "whatsapp",  # .................. Chat Clients
        "nimbusSmsIndia", "savvyBulkSmsKenya",  # ... SMS Clients
        "razorpay", "safaricomMPesaExpress",  # ..... Payment Gateways
        "theCaOfficeAi"  # .......................... Software
    ] = Field(
        description = "the third-part client that was used",
        frozen = True
    )

    authType: Literal["oauth", "auth"] = Field(
        description = "the type of authentication procedure used",
        frozen = True
    )

    firstRequestTs: AwareDatetime | None = Field(
        description = "the time (utc) at which authorization was first requested",
        frozen = True,
        default = None
    )

    lastRequestTs: AwareDatetime | None = Field(
        description = "the time (utc) at which authorization was last requested",
        frozen = False,
        default_factory = lambda: date_time.get_current_utc_date_time(as_string = False)
    )

    firstRefreshTs: AwareDatetime | None = Field(
        description = "the time (utc) at which the tokens were first refreshed",
        frozen = False,
        default = None
    )

    lastRefreshTs: AwareDatetime | None = Field(
        description = "the time (utc) at which the tokens were last refreshed",
        frozen = False,
        default = None
    )

    auth: dict = Field(
        description = "any direct auth details like api keys or passwords; will differ for each client",
        frozen = False,
        default = {}
    )

    token: dict = Field(
        description = "the actual auth tokens of that client; will differ for each client",
        frozen = False,
        default = {}
    )

    user: CoreUserInfoModel = Field(
        description = "how you identify your user",
        frozen = True
    )

    clientUserId: dict = Field(
        description = "how third-party client identifies the same user",
        frozen = False
    )

    status: Literal["pending", "active", "disabled"] = Field(
        description = "to indicate the status of this account",
        frozen = False,
        default = "pending"
    )

    syncFreq: Literal[60, 300, 1500] = Field(
        description = "the no. of seconds after which to poll for updates from the client (if applicable)",
        frozen = False,
        default = 300
    )

    # ┏┓    ┏•
    # ┃ ┏┓┏┓╋┓┏┓
    # ┗┛┗┛┛┗┛┗┗┫
    #          ┛

    class Config:
        extra = "allow"
        arbitrary_types_allowed = True

    def model_dump(self, *args, **kwargs):
        return super().model_dump(*args, by_alias = True, **kwargs)

    # ┓┏  ┓• ┓   •
    # ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓
    # ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗

    @field_validator(
        "firstRequestTs",
        "lastRequestTs", "firstRefreshTs", "lastRefreshTs",
        mode = "before"
    )
    def parse_date_time(cls, value):
        return date_time.parse_date_time(input_value = value, timezone = date_time.TIMEZONE_UTC)

    @field_validator("auth", "token", mode = "before")
    def handle_null_creds(cls, value):
        if value is None: value = {}
        return value


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                               MAIN PROGRAM                                                    ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


if __name__ == "__main__":

    from utils_v2.string import json

    auth_token = CoreAuthTokenModel(
        serviceType = "email",
        client = "gmail",
        authType = "oauth",
        firstRequestTs = date_time.get_current_utc_date_time(as_string = False),
        lastRequestTs = date_time.get_current_utc_date_time(as_string = False),
        firstRefreshTs = date_time.get_current_utc_date_time(as_string = False),
        lastRefreshTs = date_time.get_current_utc_date_time(as_string = False),
        token = {
            "username": "testing123",
            "password": "abcdefgh"
        },
        user = {
            "userId": 0,
            "entityId": 1,
            "billingAccountId": 2,
            "fullName": "Bhopli"
        },
        clientUserId = {
            "email": "bhopli@gmail.com"
        }
    )

    print("AUTH-TOKEN MODEL:", json.to_string(auth_token.model_dump(), default = str))
