"""
2025.10.26: change designate column type from Annotated to Optional and raw type.
"""

# import packages from default or pip library
from datetime import datetime, timezone
from typing_extensions import Optional
from uuid import UUID, uuid4
from sqlmodel import (SQLModel,
                      Field)

# import packages from this framework


# define Class for Common SQLModel
class IdMixin(SQLModel):
    id: int = Field(primary_key=True, default=None)

    def __setattr__(self, name, value) -> None:
        if name == "id":
            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 UUIDMixin(SQLModel):
    id: UUID = Field(primary_key=True, default=None)

    def __setattr__(self, name, value) -> None:
        if name == "id":
            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 RegisterDateTimeMixin(SQLModel):
    register_dt: datetime = Field(nullable=False, default=None)

    def __setattr__(self, name, value) -> None:
        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(SQLModel):
    update_dt: Optional[datetime] = Field(nullable=True, default=None)

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


# define function to control SQL event
# please follow the procedure below
# use decorator 'event.listens_for()' for event handling function
# event handler function must have 3 args: mapper, connection and target)
# in your model file, import listens_for from 'sqlalchemy.event'
# event.listens_for(target=TARGET_TABLE_CLASS_NAME, identifier=['before_insert', 'before_update',...])
def _assign_register_datetime(mapper, connection, target) -> None:
    if target.register_dt is None:
        target.register_dt = datetime.now(tz=timezone.utc)
    return None

def _assign_update_datetime(mapper, connection, target) -> None:
    target.renew_update_dt()
    return None

def _assign_uuid(mapper, connection, target) -> None:
    if target.id is None:
        target.id = uuid4()
    return None