# import packages from default or pip library
from datetime import datetime, timezone
from typing_extensions import deprecated, Optional
from uuid import UUID, uuid4
from mongoengine import Document, UUIDField, DateTimeField


# import packages from this framework


# define Class for Common MongoDB
@deprecated("MongoDB does not requires to set uuid manually.")
class UUIDMixin(Document):
    meta = {'abstract': True}

    id: UUID = UUIDField(primary_key=True, default=None, unique=True)


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

    register_dt: datetime = DateTimeField(null=False, default=None, db_field="register_dt")

    def __setattr__(self, name: str, value: datetime):
        if name == "register_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


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

    update_dt: Optional[datetime] = DateTimeField(null=False, default=None, db_field="update_dt")

    def renew_update_dt(self) -> None:
        super().__setattr__(name="update_dt", value=datetime.now(tz=timezone.utc))
        return None


# 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)
@deprecated("MongoDB does not requires to set uuid manually.")
def _assign_uuid(sender, document, **kwargs) -> None:
    if document.id is None:
        document.id = uuid4()
    return None

def _assign_register_datetime(sender, document, **kwargs) -> None:
    if document.register_dt is None:
        document.register_dt = datetime.now(tz=timezone.utc)
    return None

def _assign_update_datetime(sender, document, **kwargs) -> None:
    document.renew_update_dt()
    return None
