"""User domain model."""

from typing import TYPE_CHECKING

from sqlalchemy import Boolean, Column, ForeignKey, String, Table
from sqlalchemy import UUID as SQLUUID
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship

from apex.infrastructure.database.base import Base, BaseModel

if TYPE_CHECKING:
    from apex.domain.models.organization import BaseOrganization
    from apex.domain.models.role import BaseRole

# Association table for many-to-many relationship between users and roles
# Defined here to avoid circular imports
# NOTE: Association tables must use Column(), not mapped_column()
user_role_association = Table(
    "user_role_association",
    Base.metadata,
    Column("user_id", SQLUUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), primary_key=True),
    Column("role_id", SQLUUID(as_uuid=True), ForeignKey("roles.id", ondelete="CASCADE"), primary_key=True),
)


class BaseUser(BaseModel):
    """
    Abstract base user model.

    Users should extend this class to create their own User model.
    Example:
        class User(BaseUser):
            __tablename__ = "users"
    """

    __abstract__ = True

    # Basic fields (as per requirements: email, first_name, last_name, phone, country)
    email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)
    first_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
    last_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
    phone: Mapped[str | None] = mapped_column(String(50), nullable=True)
    country: Mapped[str | None] = mapped_column(String(100), nullable=True)
    hashed_password: Mapped[str] = mapped_column(String(255), nullable=False)
    
    # Status fields
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    is_verified: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    is_superuser: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    
    # Password reset token (for forgot password flow)
    reset_token: Mapped[str | None] = mapped_column(String(255), nullable=True, index=True)
    reset_token_expires: Mapped[str | None] = mapped_column(String(255), nullable=True)

    # Multi-tenant
    organization_id: Mapped[str | None] = mapped_column(
        String(36),  # UUID as string for flexibility
        ForeignKey("organizations.id", ondelete="CASCADE"),
        nullable=True,
        index=True,
    )

    # Flexible settings stored as JSONB
    settings: Mapped[dict | None] = mapped_column(JSONB, nullable=True, default=dict)

    # Relationships (will be populated when models are imported)
    organization: Mapped["BaseOrganization | None"] = relationship(
        "BaseOrganization",
        back_populates="users",
        lazy="selectin",
    )
    roles: Mapped[list["BaseRole"]] = relationship(
        "BaseRole",
        secondary=user_role_association,
        back_populates="users",
        lazy="selectin",
    )

