"""
Modelos ORM para gestión de clientes y proveedores
"""

from decimal import Decimal
from typing import Optional

from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
from sqlalchemy import (
    ForeignKey,
    ForeignKeyConstraint,
    Integer,
    Numeric,
    PrimaryKeyConstraint,
    SmallInteger,
    String,
    Enum as PgEnum,
    Boolean
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from enum import Enum

class ClientOrProviderEnum(str, Enum):
    CLIENT = "client"
    PROVIDER = "provider"
    BOTH = "both"


class ClientProvider(Base, TenantScopedMixin, TimestampMixin):
    """
    Modelo para la tabla GClientesPro - Información de clientes y proveedores
    """

    __tablename__ = "clients_and_providers"
    __table_args__ = (
        PrimaryKeyConstraint("id", name="clients_and_providers_pkey"),
        {"schema": "a76"},
    )

    # Primary key
    id: Mapped[int] = mapped_column(Integer, primary_key=True)

    # Basic information
    type_nat_foreign: Mapped[Optional[str]] = mapped_column(String(1))  # TIPO NACIONAL/EXTRANJERO
    name: Mapped[Optional[str]] = mapped_column(String(256))
    short_name: Mapped[Optional[str]] = mapped_column(String(10))
    # Identificador fiscal único: RFC (nacional) o TAX-ID (extranjero); no usar programs.tax_id para lo mismo
    rfc: Mapped[Optional[str]] = mapped_column(String(30))
    curp: Mapped[Optional[str]] = mapped_column(String(19))
    client_or_provider: Mapped[ClientOrProviderEnum] = mapped_column(PgEnum(ClientOrProviderEnum, name="entity_client_or_provider", create_type=True, native_enum=True),nullable=False)
    linking: Mapped[Optional[str]] = mapped_column(String(1))
    transform_subassembly: Mapped[Optional[str]] = mapped_column(String(1))
    extra_information: Mapped[Optional[str]] = mapped_column(String(399))
    web_key: Mapped[Optional[str]] = mapped_column(String(40))
    responsible: Mapped[Optional[str]] = mapped_column(String(80))
    position: Mapped[Optional[str]] = mapped_column(String(30))
    incoterm: Mapped[Optional[str]] = mapped_column(String(19))
    is_active: Mapped[Optional[bool]] = mapped_column(Boolean)

    # Relationships
    address: Mapped[Optional["ClientProviderAddress"]] = relationship(
        back_populates="clients_and_providers", uselist=False, cascade="all, delete-orphan"
    )
    programs: Mapped[Optional["ClientProviderPrograms"]] = relationship(
        back_populates="clients_and_providers", uselist=False, cascade="all, delete-orphan"
    )


class ClientProviderAddress(Base, TenantScopedMixin, TimestampMixin):
    """
    Modelo para la tabla GClientesPro_Direccion - Dirección de clientes y proveedores
    """

    __tablename__ = "clients_and_providers_address"
    __table_args__ = (
        PrimaryKeyConstraint("id", name="clients_and_providers_address_pkey"),
        ForeignKeyConstraint(
            ["client_id"],
            ["a76.clients_and_providers.id"],
            ondelete="CASCADE",
            name="fk_clients_and_providers_address_client",
        ),
        {"schema": "a76"},
    )

    # Primary key (foreign key)
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    client_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("a76.clients_and_providers.id", ondelete="CASCADE")
    )

    # Address information
    municipality: Mapped[Optional[str]] = mapped_column(String(150))
    streets: Mapped[Optional[str]] = mapped_column(String(100))
    neighborhood: Mapped[Optional[str]] = mapped_column(String(40))
    interior_number: Mapped[Optional[str]] = mapped_column(String(20))
    exterior_number: Mapped[Optional[str]] = mapped_column(String(20))
    postal_code: Mapped[Optional[str]] = mapped_column(String(15))
    city: Mapped[Optional[str]] = mapped_column(String(30))
    state: Mapped[Optional[str]] = mapped_column(String(30))
    country: Mapped[Optional[str]] = mapped_column(String(3))
    phone: Mapped[Optional[str]] = mapped_column(String(30))
    fax_number: Mapped[Optional[str]] = mapped_column(String(30))
    email: Mapped[Optional[str]] = mapped_column(String(100))
    contact: Mapped[Optional[str]] = mapped_column(String(50))
    reference: Mapped[Optional[str]] = mapped_column(String(250))

    # Relationship
    clients_and_providers: Mapped["ClientProvider"] = relationship(back_populates="address")


class ClientProviderPrograms(Base, TenantScopedMixin, TimestampMixin):
    """
    Modelo para la tabla GClientesPro_Programas - Programas de clientes y proveedores
    """

    __tablename__ = "clients_and_providers_programs"
    __table_args__ = (
        PrimaryKeyConstraint("id", name="clients_and_providers_programs_pkey"),
        ForeignKeyConstraint(
            ["client_id"],
            ["a76.clients_and_providers.id"],
            ondelete="CASCADE",
            name="fk_clients_and_providers_programs_client",
        ),
        {"schema": "a76"},
    )

    # Primary key (foreign key)
    id: Mapped[int] = mapped_column(Integer, primary_key=True)
    client_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("a76.clients_and_providers.id", ondelete="CASCADE")
    )

    # Program information
    program: Mapped[Optional[str]] = mapped_column(String(7))
    program_number: Mapped[Optional[str]] = mapped_column(String(40))
    prosec: Mapped[Optional[str]] = mapped_column(String(8))
    prosec_authorization: Mapped[Optional[str]] = mapped_column(String(20))
    secon_auth_date: Mapped[Optional[int]] = mapped_column(Integer)
    manufacturer_id: Mapped[Optional[str]] = mapped_column(String(25))
    broker: Mapped[Optional[str]] = mapped_column(String(6))
    import_broker: Mapped[Optional[str]] = mapped_column(String(6))
    transfer_key: Mapped[Optional[str]] = mapped_column(String(8))
    secon_authorization: Mapped[Optional[str]] = mapped_column(String(20))
    applied_proportion: Mapped[Optional[Decimal]] = mapped_column(Numeric(7, 2))
    is_certified_company: Mapped[Optional[str]] = mapped_column(String(1))
    certified_company_registry: Mapped[Optional[str]] = mapped_column(String(40))
    donation_auth_number: Mapped[Optional[str]] = mapped_column(String(50))
    ctpat_svi: Mapped[Optional[str]] = mapped_column(String(100))
    tax_registry_number: Mapped[Optional[str]] = mapped_column(String(40))
    subassembly_service: Mapped[Optional[int]] = mapped_column(SmallInteger)
    autse_dates: Mapped[Optional[int]] = mapped_column()
    autse_number: Mapped[Optional[str]] = mapped_column(String(300))

    # Relationship
    clients_and_providers: Mapped["ClientProvider"] = relationship(back_populates="programs")
