"""SQLAlchemy base model and common mixins.

This module provides the declarative base class and common column mixins
used by all database models.

Example:
    from app.db.base import Base

    class User(Base):
        __tablename__ = "users"

        email = Column(String, unique=True, nullable=False)
        display_name = Column(String, nullable=False)
"""

from datetime import datetime
from typing import Any
from uuid import uuid4

from sqlalchemy import DateTime, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import DeclarativeBase, Mapped, declared_attr, mapped_column


class Base(DeclarativeBase):
    """Base class for all SQLAlchemy models.

    Provides common columns and functionality:
    - id: UUID primary key (auto-generated)
    - created_at: Timestamp when record was created
    - updated_at: Timestamp when record was last updated

    All models should inherit from this class.

    Example:
        class User(Base):
            __tablename__ = "users"
            email: Mapped[str] = mapped_column(unique=True)
    """

    # Type annotation for type checkers
    __tablename__: str

    # Common columns for all models
    id: Mapped[str] = mapped_column(
        UUID(as_uuid=False),
        primary_key=True,
        default=lambda: str(uuid4()),
        doc="Unique identifier (UUID)",
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now(),
        nullable=False,
        doc="Timestamp when record was created",
    )

    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
        doc="Timestamp when record was last updated",
    )

    @declared_attr.directive
    @classmethod
    def __tablename__(cls) -> str:
        """Generate table name from class name.

        Converts CamelCase to snake_case and pluralizes.
        Example: UserProfile -> user_profiles

        Can be overridden by setting __tablename__ directly.
        """
        # Convert CamelCase to snake_case
        name = cls.__name__
        result = [name[0].lower()]
        for char in name[1:]:
            if char.isupper():
                result.append("_")
                result.append(char.lower())
            else:
                result.append(char)

        # Simple pluralization (add 's')
        table_name = "".join(result)
        if not table_name.endswith("s"):
            table_name += "s"
        return table_name

    def to_dict(self) -> dict[str, Any]:
        """Convert model instance to dictionary.

        Returns:
            Dictionary with all column values.
        """
        return {column.name: getattr(self, column.name) for column in self.__table__.columns}

    def __repr__(self) -> str:
        """Generate string representation of model instance."""
        class_name = self.__class__.__name__
        return f"<{class_name}(id={self.id!r})>"
