from decimal import Decimal

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

from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from api.v1.modules.fin.catalogs.models import CfdiUse, TaxRegime  # noqa: F401  (resuelve las FK)
from core.database import Base


class Account(Base, TenantScopedMixin, TimestampMixin):
    """Catálogo de Clientes / Prospectos.

    Un mismo registro puede ser Cliente o Prospecto (``record_type``). Concentra
    datos generales, comerciales y fiscales; las direcciones, contactos y
    documentos viven en tablas relacionadas (crm.addresses, crm.contacts,
    crm.documents).
    """

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

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)

    # ----- Datos generales -----
    name: Mapped[str] = mapped_column(String(255), nullable=False)  # razón social
    trade_name: Mapped[str | None] = mapped_column(String(255), nullable=True)  # nombre comercial
    rfc: Mapped[str | None] = mapped_column(String(13), nullable=True, index=True)
    curp: Mapped[str | None] = mapped_column(String(18), nullable=True)  # persona física
    # Tipo de registro: cliente | prospecto
    record_type: Mapped[str] = mapped_column(String(20), nullable=False, server_default=text("'cliente'"), index=True)
    # Tipo de persona: fisica | moral
    person_type: Mapped[str | None] = mapped_column(String(10), nullable=True)
    industry: Mapped[str | None] = mapped_column(String(120), nullable=True)  # giro / industria
    industry_other: Mapped[str | None] = mapped_column(String(120), nullable=True)  # especificar cuando giro = "otro"
    # Tipo operativo (immex | agencia_aduanal | importador | exportador | transportista | otro)
    account_type: Mapped[str | None] = mapped_column(String(40), nullable=True)
    # Estatus: active | inactive
    status: Mapped[str] = mapped_column(String(20), nullable=False, server_default=text("'active'"))

    # ----- Información comercial -----
    # Clasificación: importador | exportador | ambos
    commercial_classification: Mapped[str | None] = mapped_column(String(20), nullable=True)
    # Medio de contacto preferido: llamada | correo | videoconferencia | whatsapp | otro
    preferred_contact_method: Mapped[str | None] = mapped_column(String(20), nullable=True)
    # Texto libre cuando el medio de contacto es "otro"
    preferred_contact_other: Mapped[str | None] = mapped_column(String(120), nullable=True)
    language: Mapped[str | None] = mapped_column(String(40), nullable=True)
    email: Mapped[str | None] = mapped_column(String(255), nullable=True)
    phone: Mapped[str | None] = mapped_column(String(40), nullable=True)
    website: Mapped[str | None] = mapped_column(String(255), nullable=True)
    commercial_observations: Mapped[str | None] = mapped_column(Text, nullable=True)  # observaciones generales

    # ----- Información fiscal -----
    # Régimen fiscal y uso de CFDI en texto libre: se conservan como capturó el usuario
    # para no perder lo ya registrado, pero lo que vale al timbrar son las FK de abajo.
    tax_regime: Mapped[str | None] = mapped_column(String(120), nullable=True)  # régimen fiscal
    cfdi_use: Mapped[str | None] = mapped_column(String(60), nullable=True)  # uso de CFDI
    # Claves del receptor contra los catálogos del SAT (c_RegimenFiscal y c_UsoCFDI).
    tax_regime_id: Mapped[int | None] = mapped_column(
        Integer, ForeignKey("sat.tax_regimes.id"), nullable=True
    )
    cfdi_use_id: Mapped[int | None] = mapped_column(
        Integer, ForeignKey("sat.cfdi_uses.id"), nullable=True
    )
    payment_method: Mapped[str | None] = mapped_column(String(60), nullable=True)  # método de pago
    payment_form: Mapped[str | None] = mapped_column(String(60), nullable=True)  # forma de pago
    currency: Mapped[str | None] = mapped_column(String(3), nullable=True)  # moneda
    credit_limit: Mapped[Decimal | None] = mapped_column(Numeric(14, 2), nullable=True)
    credit_days: Mapped[int | None] = mapped_column(Integer, nullable=True)
    commercial_terms: Mapped[str | None] = mapped_column(Text, nullable=True)  # condiciones comerciales

    # ----- Datos aduaneros / ubicación rápida -----
    patente_aduanal: Mapped[str | None] = mapped_column(String(20), nullable=True)
    # Ubicación de referencia (el detalle vive en crm.addresses)
    address: Mapped[str | None] = mapped_column(Text, nullable=True)
    city: Mapped[str | None] = mapped_column(String(120), nullable=True)
    state: Mapped[str | None] = mapped_column(String(120), nullable=True)
    country: Mapped[str | None] = mapped_column(String(3), nullable=True, server_default=text("'MEX'"))

    # ----- Observaciones y auditoría -----
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)  # comentarios generales
    internal_notes: Mapped[str | None] = mapped_column(Text, nullable=True)  # notas internas
    owner_user_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)  # vendedor
    created_by: Mapped[str | None] = mapped_column(String(64), nullable=True)
    updated_by: Mapped[str | None] = mapped_column(String(64), nullable=True)
