"""
Modelos ORM para gestión de clases SCAII y SCAF
"""

from typing import TYPE_CHECKING, Optional

from api.v1.common.base_models import TenantScopedMixin, TimestampMixin
from core.database import Base
from sqlalchemy import (
    ForeignKey,
    ForeignKeyConstraint,
    Integer,
    PrimaryKeyConstraint,
    SmallInteger,
    String,
    UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from api.v1.modules.public.reference_data.material_types.models import MaterialType
from api.v1.modules.a76.general_catalogs.units_of_measure.models import UnitOfMeasure

if TYPE_CHECKING:
    from api.v1.modules.a76.parts.models import Part


class Class(Base, TenantScopedMixin, TimestampMixin):
    """
    Modelo para la tabla GClases - Información de clases en sistemas SCAII y SCAF
    """

    __tablename__ = "classes"
    __table_args__ = (
        PrimaryKeyConstraint("id", name="classes_pkey"),
        ForeignKeyConstraint(
            ["material_key"],
            ["public.material_types.key"],
            name="fk_classes_material_type",
        ),
        ForeignKeyConstraint(
            ["unit_of_measure", "tenant_id", "company_id"],
            ["a76.units_of_measure.code", "a76.units_of_measure.tenant_id",
                "a76.units_of_measure.company_id"],
        ),
        UniqueConstraint(
            "tenant_id",
            "company_id",
            "class_code",
            name="uq_classes_tenant_company_code",
        ),
        {"schema": "a76", "extend_existing": True},
    )

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

    # Unique constraint compuesta
    class_code: Mapped[str] = mapped_column(String(8))  # CLASE

    # Basic information
    description_es: Mapped[Optional[str]] = mapped_column(
        String(500))  # DESCRIPCIONE
    description_en: Mapped[Optional[str]] = mapped_column(
        String(500))  # DESCRIPCIONI

    # Material and measurement
    material_key: Mapped[Optional[str]] = mapped_column(
        String(10)
    )  # CLAVEMAT - homologated from TIPOMAT/TIPOMATEQUIPO
    unit_of_measure: Mapped[Optional[str]] = mapped_column(
        String(5)
    )  # UNIMED - homologated from UNIMEDIDA

    # Tariff fractions
    fraction: Mapped[Optional[str]] = mapped_column(String(20))  # FRACCION
    us_fraction: Mapped[Optional[str]] = mapped_column(
        String(16)
    )  # FRACCIONAME - US tariff fraction

    # Additional classification
    sub_key: Mapped[Optional[str]] = mapped_column(String(5))  # CLAVESUB
    physical_review: Mapped[Optional[int]] = mapped_column(
        SmallInteger)  # REVFISICA
    iva_exempt_fraction: Mapped[Optional[str]] = mapped_column(
        String(4)
    )  # FRACCIONEXENTAIVA

    is_active: Mapped[bool] = mapped_column(
        default=True, server_default="true", nullable=False
    )  # Campo para habilitar/deshabilitar clases sin eliminarlas

    # Relationships
    material_type: Mapped[Optional["MaterialType"]] = relationship(
        foreign_keys=[material_key]
    )
    unit_of_measure_info: Mapped[Optional["UnitOfMeasure"]] = relationship(
        foreign_keys=[unit_of_measure]
    )        

    # Inverse relationship with GParts that have this class
    parts: Mapped[list["Part"]] = relationship(
        primaryjoin="and_(Class.class_code == Part.part_class)",
        foreign_keys="[Part.part_class]",
        viewonly=True,
        back_populates="part_class_info",
    )

    def __repr__(self) -> str:
        return f"<Class(class_code='{self.class_code}', description='{self.description_es}')>"
