"""Tables du module Sites (spec 2026-08-31 §3). Colonnes = schémas de réponse, rien de plus."""

import uuid
from datetime import datetime

from sqlalchemy import (
    Boolean,
    CheckConstraint,
    DateTime,
    ForeignKey,
    Index,
    Text,
    UniqueConstraint,
    func,
    text,
)
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.db.base import Base


class Site(Base):
    __tablename__ = "sites"
    # RETURNING sur INSERT/UPDATE : id (uuidv7), created_at, updated_at sont lus au flush,
    # jamais par un SELECT de rafraîchissement.
    __mapper_args__ = {"eager_defaults": True}

    # UUIDv7 natif Postgres 18 : ordre temporel (curseur sur une seule colonne), id opaque.
    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, server_default=text("uuidv7()")
    )
    # Id Better Auth opaque — jamais de FK inter-bases. Pas d'index dédié : le btree de
    # UNIQUE (org_id, domain) est préfixé par org_id, il sert déjà les filtres par org.
    org_id: Mapped[str] = mapped_column(Text, nullable=False)
    # Hôte normalisé (app.sites.domain), forme ASCII/punycode, max 253. Immuable.
    domain: Mapped[str] = mapped_column(Text, nullable=False)
    name: Mapped[str] = mapped_column(Text, nullable=False)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now()
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
    )

    # passive_deletes : c'est le ON DELETE CASCADE de la base qui supprime les cibles.
    targets: Mapped[list["SiteTarget"]] = relationship(
        back_populates="site",
        cascade="all, delete-orphan",
        passive_deletes=True,
        order_by="SiteTarget.id",
    )

    __table_args__ = (UniqueConstraint("org_id", "domain", name="uq_sites_org_id_domain"),)


class SiteTarget(Base):
    __tablename__ = "site_targets"
    __mapper_args__ = {"eager_defaults": True}

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, server_default=text("uuidv7()")
    )
    site_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True),
        ForeignKey("sites.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    # Dénormalisé (spec §2) : toute table métier porte org_id, filtrage systématique.
    org_id: Mapped[str] = mapped_column(Text, nullable=False, index=True)
    country: Mapped[str] = mapped_column(Text, nullable=False)  # ISO 3166-1 alpha-2
    language: Mapped[str] = mapped_column(Text, nullable=False)  # ISO 639-1
    is_default: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false"))
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now()
    )

    site: Mapped[Site] = relationship(back_populates="targets")

    __table_args__ = (
        CheckConstraint("country ~ '^[A-Z]{2}$'", name="ck_site_targets_country"),
        CheckConstraint("language ~ '^[a-z]{2}$'", name="ck_site_targets_language"),
        UniqueConstraint(
            "site_id", "country", "language", name="uq_site_targets_site_country_language"
        ),
        # Exactement une cible par défaut par site, garanti par la base (spec §3.2).
        Index(
            "uq_site_targets_default", "site_id", unique=True, postgresql_where=text("is_default")
        ),
    )
