"""
Modelli Signature – firme automatiche per caselle PEC e Virtual Box.

Struttura:
  Signature           → definisce il testo della firma (con editor rich text)
  SignatureAssignment → collega una firma a una casella o virtual box per un contesto
                        (risposta, nuova composizione, o entrambi)
"""

import uuid
from datetime import datetime

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

from app.database import Base


class Signature(Base):
    """Firma riutilizzabile di un tenant."""

    __tablename__ = "signatures"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    tenant_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    body_html: Mapped[str | None] = mapped_column(Text, nullable=True)
    body_text: Mapped[str | None] = mapped_column(Text, nullable=True)
    created_by: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
    )
    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()
    )

    __table_args__ = (
        UniqueConstraint("tenant_id", "name", name="uq_signature_name_tenant"),
        Index("idx_signatures_tenant", "tenant_id"),
    )

    def __repr__(self) -> str:
        return f"<Signature {self.name!r}>"


class SignatureAssignment(Base):
    """
    Assegna una firma a una casella PEC o a una Virtual Box per un determinato contesto.

    context:
      reply   – firma inserita automaticamente nelle risposte
      compose – firma inserita automaticamente nelle nuove composizioni
      both    – firma inserita in entrambi i contesti

    Vincolo: esattamente uno tra mailbox_id e virtual_box_id deve essere valorizzato.
    Vincolo unique: non puo' esistere piu' di un'assegnazione per la stessa
                    (casella/vbox, contesto) coppia.
    """

    __tablename__ = "signature_assignments"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    tenant_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False
    )
    signature_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("signatures.id", ondelete="CASCADE"), nullable=False
    )
    mailbox_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("mailboxes.id", ondelete="CASCADE"), nullable=True
    )
    virtual_box_id: Mapped[uuid.UUID | None] = mapped_column(
        UUID(as_uuid=True), ForeignKey("virtual_boxes.id", ondelete="CASCADE"), nullable=True
    )
    # "reply" | "compose" | "both"
    context: Mapped[str] = mapped_column(String(20), nullable=False, default="both")

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), nullable=False, server_default=func.now()
    )

    __table_args__ = (
        # Almeno uno tra mailbox_id e virtual_box_id deve essere valorizzato
        CheckConstraint(
            "(mailbox_id IS NOT NULL)::int + (virtual_box_id IS NOT NULL)::int = 1",
            name="ck_sig_assignment_target",
        ),
        # Non puo' esserci piu' di un'assegnazione per la stessa casella+contesto
        UniqueConstraint("mailbox_id", "context", name="uq_sig_mailbox_context"),
        # Non puo' esserci piu' di un'assegnazione per la stessa vbox+contesto
        UniqueConstraint("virtual_box_id", "context", name="uq_sig_vbox_context"),
        Index("idx_sig_assign_tenant", "tenant_id"),
        Index("idx_sig_assign_mailbox", "mailbox_id"),
        Index("idx_sig_assign_vbox", "virtual_box_id"),
    )

    def __repr__(self) -> str:
        target = f"mailbox={self.mailbox_id}" if self.mailbox_id else f"vbox={self.virtual_box_id}"
        return f"<SignatureAssignment sig={self.signature_id} {target} ctx={self.context!r}>"
