from enum import Enum
from typing import Optional, List, TYPE_CHECKING
from sqlalchemy import (
    BigInteger,
    Boolean,
    Date,
    ForeignKey,
    Integer,
    Numeric,
    String,
    Text,
    TIMESTAMP,
    func,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from core.database import Base
from datetime import datetime
from ....common.base_models import TenantScopedMixin, TimestampMixin

if TYPE_CHECKING:
    from api.v1.modules.a76.pedmientos.models.pedimentos import Pedimentos


class Currency(str, Enum):
    FOREIGN = "foreign"
    LOCAL = "local"
    MANUAL = "manual"


class WeightUnit(str, Enum):
    KGS = "kgs"
    LBS = "lbs"


class DestinationOriginCove(str, Enum):
    EDO_BC_PARC_SON = "edo_bc_parc_son"
    ESTADO_BCS = "estado_bcs"
    ESTADO_ROO = "estado_roo"
    MPIO_SALINA_CRUZ_OAX = "mpio_salina_cruz_oxa"
    FRANJA_FRONT_NORTE = "franja_front_norte"
    INTERIOR_PAIS = "interior_pais"
    MPIO_CABORCA_SON = "mpio_caborca_son"


class OperationType(str, Enum):
    IMP = "imp"  # Importación
    EXP = "exp"  # Exportación
    SM_IN = "sm_in"  # Entrada SM
    SM_OUT = "sm_out"  # Salida SM
    CTM_SEND = "ctm_send"  # Envío CTM
    CTM_RECEIVE = "ctm_receive"  # Recibo CTM


class TransportType(str, Enum):
    NONE = "none"
    TRANSPORT = "transport"
    BOX = "box"
    PLATES = "licence plates"
    TRUCK = "truck"
    VESSEL = "vessel"
    BARGE = "rail_barge"
    CONTAINER = "container"
    AIRPLANE = "airplane"
    GONDOLA = "gondola"
    FLATBED = "flatbed"
    
class InvoiceStatus(str, Enum):
    PENDING = "pending"
    PROCESSED = "processed"    
    REVERSED = "reversed"


# --- 1. Invoice Header (invoice_header) ---
class InvoiceHeader(Base, TenantScopedMixin, TimestampMixin):
    __tablename__ = "invoice_header"
    __table_args__ = ({"schema": "a76"},)

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)

    # Identifiers
    system: Mapped[str] = mapped_column(
        String(12)
    )  # SISTEMA / Sistema de origen <-- no tiene campo en la antigua base de datos, sera para fixed_asset(scaf), inventory(scaii)
    operation_type: Mapped[OperationType] = mapped_column(
        String(11)
    )  # TIPOMOVIMIENTO / Clasifica imp/exp/sm/ctm
    invoice_type: Mapped[str] = mapped_column(
        ForeignKey("public.invoice_types.key")
    )  # TIPOFACTURA / TIPODOC
    document_type: Mapped[Optional[str]] = mapped_column(
        ForeignKey("public.pedimento_regimens.code"), nullable=True
    )
  # CLAVEDOCUMENTO / Clave de documento
    invoice_number: Mapped[str] = mapped_column(
        String(100)
    )  # FACTURAIMPO/FACTURAEXPO/FACTURAREMISION/FACTURAENVIO/FACTURASALIDA
    project_number: Mapped[Optional[str]] = mapped_column(String(14))  # NUMPROYECTO
    purchase_order: Mapped[Optional[str]] = mapped_column(String(50))  # ORDENCOMPRA
    related_doc_id: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # IDRELDOC / Para Rectificaciones
    alternate_invoice: Mapped[Optional[str]] = mapped_column(
        String(99)
    )  # FACTURAALTERNA
    invoice_ref: Mapped[Optional[str]] = mapped_column(String(19))  # FACTURAEXPOREF
    proforma_number: Mapped[Optional[str]] = mapped_column(String(20))  # NUMEROPROFORMA

    # Dates
    invoice_date: Mapped[datetime] = mapped_column(Date)  # FECHAFACTURA
    capture_date: Mapped[datetime] = mapped_column(
        TIMESTAMP(timezone=False), server_default=func.now()
    )  # FECHACAPTURA + HORAACTUAL
    emission_date: Mapped[Optional[datetime]] = mapped_column(Date)  # FECHAEMISION

    # Status & Control
    status: Mapped[InvoiceStatus] = mapped_column(String(10))  # ESTATUS
    status_rec: Mapped[Optional[InvoiceStatus]] = mapped_column(
        String(10)
    )  # ESTATUSREC / Estatus de recepción
    status_rep: Mapped[Optional[InvoiceStatus]] = mapped_column(
        String(10)
    )  # ESTATUSREP / Estatus de reporte
    processed_date: Mapped[Optional[datetime]] = mapped_column(
        TIMESTAMP(timezone=False)
    )  # FECHAACTUALIZACION / FECHAACTUAL
    who_processed: Mapped[Optional[str]] = mapped_column(
        String(100)
    )  # USUARIOACT / Quien actualizó
    capture_user: Mapped[Optional[str]] = mapped_column(
        String(100)
    )  # USUARIOCAP / Usuario que capturó

    traffic_light_status: Mapped[Optional[str]] = mapped_column(
        String(50)
    )  # SEMAFORO / SEMAFOROEXPO/IMPO
    process_log: Mapped[Optional[str]] = mapped_column(String(300))  # COMOFUEPROCESADA

    # Comments
    observation_es: Mapped[Optional[str]] = mapped_column(
        Text
    )  # OBSERVACIONE / Observaciones en español
    observation_en: Mapped[Optional[str]] = mapped_column(
        Text
    )  # OBSERVACIONI / Observaciones en inglés
    comments_status: Mapped[Optional[str]] = mapped_column(Text)  # COMENTARIOSESTATUS
    vu_observations: Mapped[Optional[str]] = mapped_column(
        String(500)
    )  # OBSERVACIONESVU / Observaciones VUCEM

    # Digital Archive Links
    cfdi_uuid: Mapped[Optional[str]] = mapped_column(String(100))  # CFDIUUID
    path_pdf: Mapped[Optional[str]] = mapped_column(String(500))  # CFDIPATHPDF
    path_xml: Mapped[Optional[str]] = mapped_column(String(500))  # CFDIPATHXML

    # Control & Subcompany
    subcompany: Mapped[Optional[str]] = mapped_column(String(5))  # SUBEMPRESA
    party_count: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # CANT_PARTIDAS / Cantidad de partidas

    # Generation flags
    generate_id: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # GENERAID
    generate_desc_parties: Mapped[Optional[str]] = mapped_column(
        String(12)
    )  # GENDESCPARTIDAS / Generar descripción de partidas
    apply_manual_discount: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # APLICADESCMANUAL

    # Bulk & Downloads
    is_bulk: Mapped[Optional[bool]] = mapped_column(Boolean)  # ESAGRANEL / Es a granel
    download_substance: Mapped[Optional[bool]] = mapped_column(
        Boolean
    )  # DESCARGASUST / Descarga de sustancia
    download_class: Mapped[Optional[bool]] = mapped_column(
        Boolean
    )  # DESCARGACLASE / Descarga de clase
    download_def: Mapped[Optional[bool]] = mapped_column(
        Boolean
    )  # DESCARGADEF / Descarga definitiva

    # Additional fields
    payment_terms: Mapped[Optional[str]] = mapped_column(
        String(200)
    )  # TERMINOSPAGO / Términos de pago
    handling_fees: Mapped[Optional[float]] = mapped_column(Numeric(19, 8))  # MANIOBRAS
    option_iv18: Mapped[Optional[str]] = mapped_column(String(50))  # OPCIONIV18
    enajenation_goods: Mapped[Optional[bool]] = mapped_column(
        Boolean
    )  # ENAJENACIONBIENES / Enajenación de bienes

    # Relationships
    compliance_mx: Mapped[Optional["InvoiceComplianceMx"]] = relationship(
        back_populates="header", cascade="all, delete-orphan", uselist=False
    )
    financials: Mapped[Optional["InvoiceFinancials"]] = relationship(
        back_populates="header", cascade="all, delete-orphan", uselist=False
    )
    details: Mapped[List["InvoiceSalesDetails"]] = relationship(
        back_populates="header", cascade="all, delete-orphan"
    )
    collections: Mapped[List["InvoiceCollections"]] = relationship(
        back_populates="header", cascade="all, delete-orphan"
    )
    logistics: Mapped[Optional["InvoiceLogistics"]] = relationship(
        back_populates="header", cascade="all, delete-orphan", uselist=False
    )


# --- 2. Compliance MX (invoice_compliance_mx) ---
class InvoiceComplianceMx(Base, TenantScopedMixin, TimestampMixin):
    __tablename__ = "invoice_compliance_mx"
    __table_args__ = ({"schema": "a76"},)

    invoice_id: Mapped[int] = mapped_column(
        ForeignKey("a76.invoice_header.id"), primary_key=True
    )

    # Core Customs Data
    pedimento_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.pedimentos.id")
    )  # PEDIMENTO/PEDIMENTOIMPO/EXPO
    pedimento_r1: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.pedimentos.id")
    )  # PEDIMENTOR1
    pedimento_k1: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.pedimentos.id")
    )  # PEDIMENTOK1
    remesa: Mapped[Optional[int]] = mapped_column(Integer)  # REMESA
    aduana: Mapped[Optional[str]] = mapped_column(
        ForeignKey("public.customs_sections.customs_code")
    )  # ADUANA_CRUCE
    port_of_entry: Mapped[Optional[str]] = mapped_column(
        String(6)
    )  # PUERTOENTRADA / Puerto de entrada
    destination: Mapped[Optional[str]] = mapped_column(
        String(3)
    )  # DESTINO / Código de destino
    manifest_number: Mapped[Optional[str]] = mapped_column(
        String(15)
    )  # MANIFIESTO / Número de manifiesto

    # Clients & Providers
    provider_header: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # PROVEEDOREXPORTADOR
    provider_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.clients_and_providers.id")
    )  # PROVEEDOR
    sold_to_header: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # VENDIDOCONSIGNADO
    sold_to_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.clients_and_providers.id")
    )  # VENDIDOA
    shipped_to_header: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # ENVIADOTRANSFERIDO
    shipped_to_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.clients_and_providers.id")
    )  # ENVIADOA
    shipped_by_header: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # ENVIADOPORVENDIDOPOR
    shipped_by_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.clients_and_providers.id")
    )  # VENDIDOPOR/ENVIADOPOR
    customs_broker_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.customs_brokers.id")
    )  # AADUANAL / Agente aduanal
    customs_broker_us_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("a76.customs_brokers.id")
    )  # AADUANALAME / Agente aduanal americano

    # Broker Invoice
    broker_invoice_num: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # NUMFACTURABROKER / Número factura broker
    broker_invoice_date: Mapped[Optional[datetime]] = mapped_column(
        Date
    )  # FECHAFACBROKER / Fecha factura broker

    # Flags & Specific Regimes
    is_mixed: Mapped[Optional[bool]] = mapped_column(Boolean)  # ESMIXTO / Es mixto
    waste_type: Mapped[Optional[str]] = mapped_column(
        String(1)
    )  # TIPODESPERDICIO / Tipo de desperdicio
    scrap_type: Mapped[Optional[str]] = mapped_column(
        String(1)
    )  # TIPOSCRAP / Tipo de scrap
    appendix_17: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # APENDICE17 / Apéndice 17
    is_regime_change: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # ESCAMBIOREGIMEN / Es cambio de régimen
    which_exchange_rate: Mapped[Optional[str]] = mapped_column(
        String(5)
    )  # CUALTIPOCAMBIO / Cuál tipo de cambio
    value_method: Mapped[Optional[str]] = mapped_column(
        String(2)
    )  # METVALOR / Método de valoración
    act_value: Mapped[Optional[str]] = mapped_column(
        String(5)
    )  # ACTVALOR / Actualizar valor
    rule_3121_parties_ii: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # REGLA3121PARTESII / Regla 3.1.21 Partes II
    is_pedimento_pending: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # PED_PENDIENTE_ASIGNAR (Mapear 1 -> True, 0 -> False)

    # Ownership & Balances
    is_owner_of_goods: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # ESDUENOMCIA / Es dueño de mercancía
    generate_balances: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # GENERARSALDOS / Generar saldos
    was_reviewed_by_company: Mapped[Optional[bool]] = mapped_column(
        Boolean
    )  # FUEREVISADAMCIA / Fue revisada por la compañía

    # VUCEM / Digital
    edocument: Mapped[Optional[str]] = mapped_column(
        String(50)
    )  # EDOCUMENT / Documento electrónico
    electronic_signature: Mapped[Optional[str]] = mapped_column(
        String(999)
    )  # FIRMAELECTRONICA / Firma electrónica
    certificate_number: Mapped[Optional[str]] = mapped_column(
        String(99)
    )  # NUMEROCERTIFICADO / Número de certificado
    niu_number: Mapped[Optional[str]] = mapped_column(
        String(19)
    )  # NUMERONIU / Número NIU
    bill_of_lading_count: Mapped[Optional[str]] = mapped_column(
        String(12)
    )  # CANTGUIASEMBARQUE / Cantidad guías embarque
    addendum_vu: Mapped[Optional[str]] = mapped_column(
        String(204)
    )  # ADENDAVU / Adenda VUCEM
    origin_destination_cove: Mapped[Optional[DestinationOriginCove]] = mapped_column(
        String(20)
    )  # DESTINOORIGENCOVE / Destino/Origen COVE
    vucem_operation_num: Mapped[Optional[str]] = mapped_column(
        String(19)
    )  # NUMOPERACIONVU / Número operación VUCEM
    customs_person_line: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # LINEAPERSONAAA / Línea persona agente aduanal

    # Additional Control
    contingency_mode: Mapped[Optional[bool]] = mapped_column(
        Boolean
    )  # MODOCONTINGENCIA / Modo contingencia
    enclosure: Mapped[Optional[str]] = mapped_column(
        String(4)
    )  # RECINTO / Recinto fiscal
    guide_type_to_identify: Mapped[Optional[str]] = mapped_column(
        String(1)
    )  # TIPODEGUIAAIDENTIFICAR / Tipo de guía a identificar
    location: Mapped[Optional[str]] = mapped_column(
        String(200)
    )  # LOCALIZACION / Localización

    # DOT & Official
    dot_code: Mapped[Optional[str]] = mapped_column(String(20))  # CLAVEDOT / Clave DOT
    subdivision: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # SUBDIVISION / Subdivisión
    acts_as: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # FUNGECOMOCO / Funge como
    movement_type: Mapped[Optional[str]] = mapped_column(
        String(31)
    )  # TIPOMOV / Tipo de movimiento
    office_document: Mapped[Optional[str]] = mapped_column(
        String(30)
    )  # OFICIO / Oficio
    reason_export: Mapped[Optional[str]] = mapped_column(
        String(1)
    )  # RAZONEXPORTACION / Razón de exportación
    signature_key: Mapped[Optional[str]] = mapped_column(
        String(100)
    )  # CLAVEFIRMA / Clave de firma

    # SM specific
    sem_id: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # SEM / ID SEM (de SFacEntradaSM/SFacSalidaSM)

    # Relationships
    header: Mapped["InvoiceHeader"] = relationship(back_populates="compliance_mx")
    pedimento: Mapped[Optional["Pedimentos"]] = relationship(
        foreign_keys=[pedimento_id], lazy="joined"
    )


# --- 3. Financials (invoice_financials) ---
class InvoiceFinancials(Base, TenantScopedMixin, TimestampMixin):
    __tablename__ = "invoice_financials"
    __table_args__ = ({"schema": "a76"},)

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))

    # Currency
    currency: Mapped[Currency] = mapped_column(
        String(7)
    )  # CLAVEMONEDA / Clave de moneda
    currency_type: Mapped[Optional[str]] = mapped_column(
        ForeignKey("public.currency_types.code")
    )  # TIPOMONEDA / TIPOCLAVEMONEDA
    exchange_rate: Mapped[Optional[float]] = mapped_column(
        Numeric(13, 6)
    )  # TIPOCAMBIO / Tipo de cambio
    exchange_rate_mm: Mapped[Optional[float]] = mapped_column(
        Numeric(13, 6)
    )  # TIPOCAMBIOMM / Tipo de cambio moneda a moneda

    # Merchandise Values (MN = National Currency, ME = Foreign Currency, MC = Third Currency)
    value_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORIMPOMN/VALOREXPOMN/VALORENTMN/VALORSALMN
    value_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORIMPOME/VALOREXPOME/VALORENTME/VALORSALME
    value_mc: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORIMPOMC/VALOREXPOMC

    # Customs Value
    customs_value_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORADUANASMN / Valor en aduanas MN
    customs_value_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORADUANASME / Valor en aduanas ME

    # Raw Materials
    raw_material_value_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORMPMN / Valor materia prima MN
    raw_material_value_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORMPME / Valor materia prima ME

    # Aggregate Value
    aggregate_value_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORAGREMN / Valor agregado MN
    aggregate_value_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORAGREME / Valor agregado ME
    aggregate_value_mc: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORAGREMC / Valor agregado MC

    # Mexican Merchandise Value
    mexican_value_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORVMEXMN / Valor mercancía mexicana MN
    mexican_value_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORVMEXME / Valor mercancía mexicana ME
    mexican_value_mc: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORVMEXMC / Valor mercancía mexicana MC

    # National Packaging
    national_packaging_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALEMPAQUENACMN / Valor empaque nacional MN
    national_packaging_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALEMPAQUENACME / Valor empaque nacional ME
    national_packaging_mc: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALEMPAQUENACMC / Valor empaque nacional MC

    # Costs & Increments
    freight: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8), default=0, server_default="0"
    )  # FLETE / Flete
    insurance: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8), default=0, server_default="0"
    )  # SEGUROS / Seguros
    insurance_value: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8), default=0, server_default="0"
    )  # VALSEGUROS / Valor seguros
    packaging: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8), default=0, server_default="0"
    )  # EMBALAJES / Embalajes
    other_increments: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8), default=0, server_default="0"
    )  # OTROSINCREMENTA / Otros incrementables
    other_deductibles: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8), default=0, server_default="0"
    )  # OTROSDEDUCIBLES / Otros deducibles
    total_increments_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # TOTALINCREMMN / Total incrementables MN
    total_increments_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # TOTALINCREMME / Total incrementables ME

    # Taxes
    iva_mn: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # IVAEXPOMN/VALORIVAMN / IVA en MN
    iva_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # IVAEXPOME/VALORIVAME / IVA en ME
    iva_mc: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # IVAEXPOMC / IVA en MC
    iva_factor: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # FACTORIVA / Factor IVA
    tax_value_me: Mapped[Optional[float]] = mapped_column(
        Numeric(23, 8), default=0, server_default="0"
    )  # VALORIMPUESTOME / Valor impuesto ME
    seal_value_2500: Mapped[Optional[bool]] = mapped_column(
        Boolean
    )  # SELLOVALOR2500 / Sello valor 2500

    # Weights & Quantities
    total_quantity: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8)
    )  # CANTEXPO/CANTIMPO / Cantidad total
    total_packages: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # CANTBULTOS / Cantidad de bultos    
    gross_weight: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8)
    )  # PESOBRUTO / Peso bruto
    net_weight: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8)
    )  # PESONETO / Peso neto
    bundle_count: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # CANTBULTOS / Cantidad de bultos
    weight_factor: Mapped[Optional[float]] = mapped_column(
        Numeric(19, 8)
    )  # FACTORPESO / Factor de peso

    # Relationship
    header: Mapped["InvoiceHeader"] = relationship(back_populates="financials")


# --- 4. Logistics (invoice_logistics) ---
class InvoiceLogistics(Base, TenantScopedMixin, TimestampMixin):
    __tablename__ = "invoice_logistics"
    __table_args__ = ({"schema": "a76"},)

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))

    # Carrier Info
    carrier_id: Mapped[Optional[str]] = mapped_column(
        String(10)
    )  # TRANSPORTISTA / Transportista
    carrier_int_id: Mapped[Optional[int]] = mapped_column(
        BigInteger, ForeignKey("a76.transporter.transporter_id"), nullable=True
    )  # Internal surrogate ID for Transporter (by transporter_key)
    transport_id: Mapped[Optional[str]] = mapped_column(
        String(10)
    )  # NUMTRAILER / Transportista
    transport_int_id: Mapped[Optional[int]] = mapped_column(
        BigInteger, ForeignKey("a76.vehicle.vehicle_id"), nullable=True
    )  # Internal surrogate ID for Vehicle (by vehicle_key)
    transport_us_id: Mapped[Optional[str]] = mapped_column(
        String(10)
    )  # TRANSPORTISTAAME / Transportista americano
    transport_type: Mapped[TransportType] = mapped_column(
        String(15), server_default="none"
    )  # TRANSPORTE / Tipo de transporte
    transport_num: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # NUMTRASPORTE / Número de transporte
    transport_mode: Mapped[Optional[str]] = mapped_column(
        String(15)
    )  # MODTRANS / Modo de transporte
    driver_name: Mapped[Optional[str]] = mapped_column(
        String(80)
    )  # CONDUCTOR / Nombre del conductor
    is_rail: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # ESFERROCARRIL / Es ferrocarril
    rail_id: Mapped[Optional[str]] = mapped_column(
        String(31)
    )  # IDFERRORCARRIL / ID ferrocarril

    # Vehicle & Tracking
    vehicle_num: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # NUMVEHICULO / Número de vehículo
    license_plate: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # NUMTRASPORTE / Número de transporte/placa
    license_plate_complete: Mapped[Optional[str]] = mapped_column(
        String(40)
    )  # NUMTRASPORTECOMPLE / Número transporte completo
    trailer_num: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # NUMTRAILER / Número de trailer
    trailer_int_id: Mapped[Optional[int]] = mapped_column(
        BigInteger, ForeignKey("a76.trailer.trailer_id"), nullable=True
    )  # Internal surrogate ID for Trailer (by trailer_number)
    seal_number: Mapped[Optional[str]] = mapped_column(
        String(15)
    )  # PRECINTO / Precinto
    guide_number: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # NUMEROGUIA / Número de guía
    bill_number: Mapped[Optional[str]] = mapped_column(
        String(15)
    )  # BILLNUMBER / Número de bill
    reference_number: Mapped[Optional[str]] = mapped_column(
        String(14)
    )  # NUMREFERENCIA / Número de referencia
    shipment_number: Mapped[Optional[str]] = mapped_column(
        String(19)
    )  # NUMEMBARQUE / Número de embarque

    # Incoterms
    incoterm: Mapped[Optional[str]] = mapped_column(
        String(5)
    )  # INCOTERM / Término de comercio internacional

    # Identifiers & Complements
    identifier_1: Mapped[Optional[str]] = mapped_column(
        String(2)
    )  # IDENTIFICADOR / Identificador 1
    complement_1: Mapped[Optional[str]] = mapped_column(
        String(30)
    )  # COMPLEMENTO1 / Complemento 1
    identifier_2: Mapped[Optional[str]] = mapped_column(
        String(2)
    )  # IDENTIFICADOR2 / Identificador 2
    complement_2: Mapped[Optional[str]] = mapped_column(
        String(30)
    )  # COMPLEMENTO2 / Complemento 2

    # Weight & Container Info
    weight_type: Mapped[WeightUnit] = mapped_column(
        String(3)
    )  # TIPOPESO / Tipo de peso
    container_types: Mapped[Optional[str]] = mapped_column(
        String(500)
    )  # CONTENEDORESTIPO / Tipos de contenedores
    vehicle_data: Mapped[Optional[str]] = mapped_column(
        String(500)
    )  # DATOSVEHICULO / Datos del vehículo

    # Locations & Routes
    origin_location: Mapped[Optional[str]] = mapped_column(
        String(200)
    )  # ORIGENUBICACION / Ubicación de origen
    destination_location: Mapped[Optional[str]] = mapped_column(
        String(200)
    )  # DESTINOUBICACION / Ubicación de destino
    transport_itinerary: Mapped[Optional[str]] = mapped_column(
        String(1000)
    )  # ITINERARIOTRANPORTE / Itinerario del transporte
    destination_goods: Mapped[Optional[str]] = mapped_column(
        String(50)
    )  # DESTINOMCIA / Destino de mercancía

    # Logistics Dates
    entry_exit_date: Mapped[Optional[datetime]] = mapped_column(
        Date
    )  # FECHAENTRADA/FECHAENVIO/FECHARECIBO / Fecha entrada/salida
    delivery_date: Mapped[Optional[datetime]] = mapped_column(
        Date
    )  # FECHAENTREGA / Fecha de entrega

    # Delivery Control
    delivered_status: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # ENTREGADO / Estado de entrega
    received_by: Mapped[Optional[str]] = mapped_column(
        String(50)
    )  # RECIBIDOPOR / Recibido por

    # Payment Info
    payment_date: Mapped[Optional[datetime]] = mapped_column(
        Date
    )  # FECHAPAGO / Fecha de pago
    payment_receipt_num: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # NUMRECIBOPAGO / Número de recibo de pago

    # CTM Process
    is_ctm_process: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False, server_default="false"
    )  # SETRATAPROCESOCTM / Se trata de proceso CTM

    # Continuation Tab Fields
    equipment_reviewed: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Fue revisado el equipo
    is_subdivision: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Sub división
    acts_as_cd: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Funge como CD
    pedimento_arrived: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Llegó el pedimento
    green_light_mx: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Semáforo verde México
    green_light_us: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Semáforo verde USA
    red_light_mx: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Semáforo rojo México
    red_light_us: Mapped[Optional[bool]] = mapped_column(
        Boolean, default=False
    )  # Semáforo rojo USA

    # Relationship
    header: Mapped["InvoiceHeader"] = relationship(back_populates="logistics")


# --- 5. Sales Order Details (invoice_sales_details) ---
class InvoiceSalesDetails(Base, TenantScopedMixin, TimestampMixin):
    __tablename__ = "invoice_sales_details"
    __table_args__ = ({"schema": "a76"},)

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))

    line_number: Mapped[int] = mapped_column(Integer)  # LINEA / Número de línea
    sales_order: Mapped[Optional[str]] = mapped_column(
        String(20)
    )  # ORDENVENTA / Orden de venta

    # Specific Custom Fields
    colors_description: Mapped[Optional[str]] = mapped_column(
        String(49)
    )  # COLORES / Descripción de colores
    square_color_code: Mapped[Optional[str]] = mapped_column(
        String(1)
    )  # COLORCUADRITO / Código de color cuadrito
    line_bundles: Mapped[Optional[int]] = mapped_column(
        Integer
    )  # CANTBULTOS / Cantidad de bultos de la línea

    # Relationship
    header: Mapped["InvoiceHeader"] = relationship(back_populates="details")


# --- 6. Collections (invoice_collections) ---
class InvoiceCollections(Base, TenantScopedMixin, TimestampMixin):
    __tablename__ = "invoice_collections"
    __table_args__ = ({"schema": "a76"},)

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
    invoice_id: Mapped[int] = mapped_column(ForeignKey("a76.invoice_header.id"))

    line_number: Mapped[int] = mapped_column(Integer)  # LINEA / Número de línea
    invoice_number: Mapped[Optional[str]] = mapped_column(
        String(15)
    )  # FACTURA / Número de factura
    concept: Mapped[Optional[str]] = mapped_column(String(100))  # CONCEPTO / Concepto

    # Relationship
    header: Mapped["InvoiceHeader"] = relationship(back_populates="collections")
