import arrow

from sqlalchemy import (
    TIMESTAMP,
    func,
    text,
    UUID,
    String,
    Integer,
    Boolean,
    SmallInteger,
)
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy_mixins.serialize import SerializeMixin
from sqlalchemy_mixins.repr import ReprMixin
from sqlalchemy_mixins.smartquery import SmartQueryMixin

from Controllers.Postgres.base import BaseAlchemyModel
from Controllers.Postgres.crud import CRUDModel
from Controllers.Postgres.filter import QueryModel
from Controllers.Postgres.database import Base


class BasicMixin(
    Base,
    BaseAlchemyModel,
    CRUDModel,
    SerializeMixin,
    ReprMixin,
    SmartQueryMixin,
    QueryModel,
):

    __abstract__ = True
    __repr__ = ReprMixin.__repr__


class CrudMixin(BasicMixin):
    """
    Base mixin providing CRUD operations and common fields for PostgreSQL models.

    Features:
    - Automatic timestamps (created_at, updated_at)
    - Soft delete capability
    - User tracking (created_by, updated_by)
    - Data serialization
    - Multi-language support
    """

    __abstract__ = True

    # Primary and reference fields
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    uu_id: Mapped[str] = mapped_column(
        UUID,
        server_default=text("gen_random_uuid()"),
        index=True,
        unique=True,
        comment="Unique identifier UUID",
    )

    # Common timestamp fields for all models
    expiry_starts: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True),
        server_default=func.now(),
        comment="Record validity start timestamp",
    )
    expiry_ends: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True),
        default=str(arrow.get("2099-12-31")),
        server_default=func.now(),
        comment="Record validity end timestamp",
    )

    # Timestamps
    created_at: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True),
        server_default=func.now(),
        nullable=False,
        index=True,
        comment="Record creation timestamp",
    )
    updated_at: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True),
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
        index=True,
        comment="Last update timestamp",
    )


class CrudCollection(CrudMixin):
    """
    Full-featured model class with all common fields.

    Includes:
    - UUID and reference ID
    - Timestamps
    - User tracking
    - Confirmation status
    - Soft delete
    - Notification flags
    """

    __abstract__ = True
    __repr__ = ReprMixin.__repr__

    # Outer reference fields
    ref_id: Mapped[str] = mapped_column(
        String(100), nullable=True, index=True, comment="External reference ID"
    )
    replication_id: Mapped[int] = mapped_column(
        SmallInteger, server_default="0", comment="Replication identifier"
    )

    # Cryptographic and user tracking
    cryp_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, index=True, comment="Cryptographic UUID"
    )

    # Token fields of modification
    created_credentials_token: Mapped[str] = mapped_column(
        String, nullable=True, comment="Created Credentials token"
    )
    updated_credentials_token: Mapped[str] = mapped_column(
        String, nullable=True, comment="Updated Credentials token"
    )
    confirmed_credentials_token: Mapped[str] = mapped_column(
        String, nullable=True, comment="Confirmed Credentials token"
    )

    # Status flags
    is_confirmed: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Record confirmation status"
    )
    deleted: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Soft delete flag"
    )
    active: Mapped[bool] = mapped_column(
        Boolean, server_default="1", comment="Record active status"
    )
    is_notification_send: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Notification sent flag"
    )
    is_email_send: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Email sent flag"
    )
