from datetime import datetime
from decimal import Decimal
from typing import List, Optional, Literal
from pydantic import BaseModel, Field, ConfigDict
from api.v1.modules.a24.inv.inv_aphis.dto import InvPartAphisGeneralDTO

# --- SUB-DTO: DATOS ADUANALES (FaData) ---
class FaDataDTO(BaseModel):
    origin_country: Optional[str] = None
    sector: Optional[str] = None
    fraction_type: Optional[str] = None

    model_config = ConfigDict(from_attributes=True)

# --- SUB-DTO: RELACIONES CON PAÍSES ---
class PartCountryDataDTO(BaseModel):
    country_code: Optional[str] = None
    fraction: Optional[str] = None
    preference: Optional[str] = "GENERAL"
    has_certificate: Optional[bool] = False
    certificate_number: Optional[str] = None
    end_date: Optional[datetime] = None
    previous_fractions_7m: Optional[bool] = False
    omission_import: Optional[bool] = False
    omission_export: Optional[bool] = False
    import_percentage: Optional[Decimal] = None
    export_percentage: Optional[Decimal] = None
    sector: Optional[str] = None

    model_config = ConfigDict(from_attributes=True)

# --- SUB-DTO: COMPONENTES BOM ---
class InvBomItemDTO(BaseModel):
    id: Optional[int] = None
    component_part_id: Optional[int] = Field(None, gt=0, description="ID de la parte componente (debe ser > 0)")
    component_part_number: Optional[str] = None
    quantity: Optional[Decimal] = Field(Decimal('1.0'), gt=0, description="Cantidad debe ser > 0")
    uom_code: Optional[str] = Field(None, max_length=5, description="Código de unidad de medida")
    procedure_type: Optional[str] = None
    is_percentage: Optional[bool] = True
    raw_material: Optional[Decimal] = None
    waste: Optional[Decimal] = None
    merma: Optional[Decimal] = None

    model_config = ConfigDict(from_attributes=True)

# --- SUB-DTO: DATOS DE INVENTARIO Y COSTEO (InvData) ---
class InvDataDTO(BaseModel):
    part_type: Optional[str] = None
    material_type: Optional[str] = None
    reference_number: Optional[str] = None
    flex_reference_number: Optional[str] = None
    equivalent_uom: Optional[str] = None
    conversion_factor: Optional[Decimal] = None
    stock_uom: Optional[str] = None
    alternate_uom: Optional[str] = None
    conversion_uom: Optional[str] = None
    added_value: Optional[Decimal] = None
    added_value_type: Optional[str] = None
    assigned_client: Optional[str] = None
    supplier_code: Optional[str] = None
    is_textile: Optional[str] = None
    bom_version: Optional[int] = None
    is_repair: Optional[str] = None
    is_hazardous: Optional[str] = None
    emergency_number: Optional[str] = None
    danger_class: Optional[str] = None
    packaging_group: Optional[str] = None
    width: Optional[str] = None
    thickness: Optional[str] = None
    specification: Optional[str] = None
    
    # Desglose de Costos (Anexo 24 - Valor Agregado)
    total_value: Optional[Decimal] = None
    direct_labor: Optional[Decimal] = None
    general_expenses: Optional[Decimal] = None
    total_expenses: Optional[Decimal] = None
    depreciation: Optional[Decimal] = None
    tooling: Optional[Decimal] = None
    material_consumed: Optional[Decimal] = None
    profit: Optional[Decimal] = None
    
    # Fracciones adicionales y TLCAN/T-MEC
    us_fraction_alt: Optional[str] = None
    ca_fraction: Optional[str] = None
    ad_valorem_us: Optional[Decimal] = None
    nafta_result: Optional[str] = None
    nafta_percentage: Optional[Decimal] = None
    dta: Optional[str] = None
    dtb: Optional[str] = None
    dtg: Optional[str] = None

    # --- CAMPOS ADICIONALES FRONTEND ---
    substitute_part: Optional[str] = None
    complementary_part: Optional[str] = None
    preference_part: Optional[str] = None
    use_alternate_quantity: Optional[bool] = False
    un_number: Optional[str] = None
    shipping_name: Optional[str] = None
    hazard_notes: Optional[str] = None
    repair_unit_cost: Optional[Decimal] = None
    repair_added_value: Optional[Decimal] = None
    fraction_9801: Optional[str] = None
    immex_type: Optional[str] = None
    disable_movements: Optional[bool] = False
    pga_program_code: Optional[str] = None
    usmca_fraction: Optional[str] = None
    scrap_part_number: Optional[str] = None
    waste_part_number: Optional[str] = None
    scrap_description_en: Optional[str] = None
    scrap_description_es: Optional[str] = None
    scrap_export_fraction: Optional[str] = None
    scrap_us_fraction: Optional[str] = None
    equivalent_uom_2: Optional[str] = None
    conversion_factor_2: Optional[Decimal] = None
    has_auxiliary: Optional[bool] = False
    auxiliary_uom: Optional[str] = None
    auxiliary_conversion: Optional[Decimal] = None
    auxiliary_unit_cost: Optional[Decimal] = None
    mex_packing: Optional[Decimal] = None
    sales_order: Optional[str] = None
    use_rule_8: Optional[bool] = False
    sector: Optional[str] = None
    origin_country: Optional[str] = None
    fraction_type: Optional[str] = None
    
    # Extensiones
    agency_code_definition: Optional[str] = None
    carta_porte: Optional[str] = None
    client_part_names: Optional[List[dict]] = None
    part_identifiers: Optional[List[dict]] = None
    substitute_parts: Optional[List[dict]] = None
    aphis_data: Optional[dict] = None
    aphis_records: Optional[List[InvPartAphisGeneralDTO]] = None
    
    non_discharge_clients: Optional[List[dict]] = None

    # Lista de materiales (BOM)
    bom_items: Optional[List[InvBomItemDTO]] = None
    
    # Lista de países de origen
    countries: Optional[List[PartCountryDataDTO]] = None

    model_config = ConfigDict(from_attributes=True)


class PartBase(BaseModel):
    part_number: str = Field(..., max_length=70)
    commercial_part_number: Optional[str] = None
    
    description_spanish: Optional[str] = None
    description_english: Optional[str] = None
    part_class: Optional[str] = None
    unit_of_measure: Optional[str] = "PZ"
    
    unit_cost: Optional[Decimal] = Field(default=None, ge=0)
    currency_key: Optional[str] = None
    currency_type: Optional[str] = None
    
    unit_weight: Optional[Decimal] = Field(default=None, ge=0)
    weight_type: Optional[str] = None
    
    fraction: Optional[str] = None
    us_fraction: Optional[str] = None
    
    # Regulatorios
    fda_key: Optional[str] = None
    fcc_key: Optional[str] = None
    license_code: Optional[str] = None
    eccn: Optional[str] = None
    export_code: Optional[str] = None
    exclusion_symbol: Optional[str] = None
    
    is_active: bool = True
    part_photo: Optional[str] = None

    # Anidados
    fa_data: Optional[FaDataDTO] = None
    inv_data: Optional[InvDataDTO] = None

# --- CREACIÓN ---
class PartCreateDTO(PartBase):
    # Opcional para que lo tome de la URL si no viene en el body
    company_id: Optional[int] = None 

# --- ACTUALIZACIÓN ---
class PartUpdateDTO(PartBase):
    part_number: Optional[str] = None
    # Todo opcional para PATCH
    pass

# --- RESPUESTA ---
class PartResponseDTO(PartBase):
    id: int
    tenant_id: int
    company_id: int
    creation_date: Optional[int] = None
    modification_date_iso: Optional[datetime] = None

    model_config = ConfigDict(from_attributes=True)

# --- BÁSICO (Para listados ligeros) ---
class PartBasicDTO(BaseModel):
    id: int
    part_number: str
    description_spanish: Optional[str] = None
    fraction: Optional[str] = None
    is_active: bool
    
    model_config = ConfigDict(from_attributes=True)

# --- LISTADO PAGINADO ---
class PartListResponseDTO(BaseModel):
    items: List[PartResponseDTO]
    total: int
    page: int
    page_size: int
    pages: int

