from sqlalchemy import ForeignKey, Integer, String, Text, text
from sqlalchemy.orm import Mapped, mapped_column

from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base


class Case(Base, TenantScopedMixin, TimestampMixin):
    """Expediente: hilo maestro de un trámite (Oportunidad → Solicitud → Cotización →
    Operación → Factura). Una sola referencia (``EXP…``) que agrupa toda la historia.
    Nace al crear la Oportunidad y se hereda a las entidades siguientes vía ``case_id``.
    """

    __tablename__ = "cases"
    __table_args__ = {"schema": "crm"}

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
    reference: Mapped[str | None] = mapped_column(String(40), nullable=True, index=True)  # folio EXP...
    account_id: Mapped[int | None] = mapped_column(
        Integer, ForeignKey("crm.accounts.id"), nullable=True, index=True
    )
    title: Mapped[str | None] = mapped_column(String(255), nullable=True)
    # Etapa más avanzada alcanzada: oportunidad|solicitud|cotizacion|operacion|facturacion|cerrado
    stage: Mapped[str] = mapped_column(String(20), nullable=False, server_default=text("'oportunidad'"))
    # abierto | cerrado
    status: Mapped[str] = mapped_column(String(20), nullable=False, server_default=text("'abierto'"), index=True)
    created_by: Mapped[str | None] = mapped_column(String(64), nullable=True)
    updated_by: Mapped[str | None] = mapped_column(String(64), nullable=True)

    # ── Espejo del carril hacia EFC (T2026-08-046) ──────────────────────────────────────────
    # EFC es la fuente única de los documentos del expediente: cada expediente se refleja allá
    # como un *pedimento provisional* y los archivos viven en su MinIO, no en el del CRM.
    #
    # Estas columnas son un ESPEJO, nunca el handle. El handle con el que el CRM habla de este
    # expediente es su ``id`` y su ``reference``: ``efc_pedimento_id`` es un caché de la
    # resolución, y del lado de EFC el ``pedimento_app`` es mutable —se reescribe al completar
    # el provisional con la data aduanera real—, así que apoyarse en él rompería justo cuando
    # llegue esa data. La liga vive en EFC, en la tabla desechable ``pedimento_expediente``.
    efc_organizacion_id: Mapped[str | None] = mapped_column(String(36), nullable=True)
    efc_pedimento_id: Mapped[str | None] = mapped_column(String(36), nullable=True)
    # INMUTABLE una vez asignado: es la carpeta de MinIO donde EFC guarda los objetos de este
    # expediente. Que no cambie nunca es lo que permite completar el pedimento sin mover ni un
    # archivo.
    efc_storage_token: Mapped[str | None] = mapped_column(String(25), nullable=True)
    # PENDING | LINKED | FAILED
    efc_link_state: Mapped[str] = mapped_column(
        String(20), nullable=False, server_default=text("'PENDING'"), index=True
    )
    # El diagnóstico se guarda en la fila para que se vea en la ficha del expediente, sin
    # obligar a nadie a ir a los logs del worker.
    efc_error_code: Mapped[str | None] = mapped_column(String(60), nullable=True)
    efc_error_detail: Mapped[str | None] = mapped_column(Text, nullable=True)
