# import packages from default or pip library
from datetime import datetime, timedelta, timezone
from mongoengine import Document, DateTimeField, StringField

# import packages from this framework
from settings import AUTHENTICATION


# settings
TOKEN_VALID_TIME: int = AUTHENTICATION.get("token").get("token_valid_time")

# define classes
class AccessTokenMixin(Document):
    meta = {'abstract': True}

    access_token: str = StringField(primary_key=True,
                                    null=False,
                                    unique=True)


class RefreshTokenMixin(Document):
    meta = {'abstract': True}

    refresh_token: str = StringField(null=False,
                                     unique=True)


class TokenValidDateTime(Document):
    """
    This class is for token management.
    it can be stored on your DB as a whitelist.
    """

    meta = {'abstract': True}

    issued_dt: datetime = DateTimeField(null=False)
    expiration_dt: datetime = DateTimeField(null=False)

    def __setattr__(self, name: str, value: datetime):
        if name in ["issued_at", "expiration_dt",]:
            if hasattr(self, name) and getattr(self, name) is not None:
                raise ValueError(f"[Warning] it is not allowed to edit value of column '{name}' in '{self.__class__}' directly.")

        super().__setattr__(name, value)
        return None

    def set_token_datetime(self) -> None:
        if self.issued_dt is None:
            super().__setattr__(name="issued_at", value=datetime.now(tz=timezone.utc))

        if self.expiration_dt is None:
            super().__setattr__(name="expiration_dt", value=datetime.now(tz=timezone.utc) + timedelta(minutes=TOKEN_VALID_TIME))

        return None


class JWTTokens(RefreshTokenMixin, AccessTokenMixin):
    meta = {'abstract': True}

    token_type: str = StringField(null=False,
                                  default="Bearer")


# define function to control MongoDB document event
# please follow the procedure below
# create event handler function with name starting with _.
# event handler function must have 3 args: sender, document, **kwargs)
# each db column can get from 'document'
# import pre_init or pre_save from 'mongoengine.signals' in your model file.
# pre_init.connect(EVNET_HANDLER_FUNC_NAME, sender=TABLE_CLASS_NAME)
def _fill_token_datetime_field(sender, document, **kwargs) -> None:
    document.set_token_datetime()
    return None
