"""
DTOs para fracciones arancelarias americanas
"""

from datetime import datetime
from typing import Optional, Any

from pydantic import BaseModel, Field, ConfigDict, model_validator
import re


class USTariffFractionCreateDTO(BaseModel):
    """DTO para crear fracción arancelaria americana"""

    code: str = Field(..., max_length=16, description="Código de fracción americana")
    prefix: Optional[str] = Field(None, max_length=10, description="Prefijo")
    type_code: Optional[str] = Field(None, max_length=10, description="Código de tipo")
    ad_valorem: Optional[float] = Field(None, description="Porcentaje ad valorem")
    fixed_cost: Optional[float] = Field(None, description="Tasa fija")
    unit_of_measure: Optional[str] = Field(None, max_length=10, description="Unidad de medida")
    description: Optional[str] = Field(None, description="Descripción")


class USTariffFractionUpdateDTO(BaseModel):
    """DTO para actualizar fracción arancelaria americana"""

    code: Optional[str] = Field(None, max_length=16)
    prefix: Optional[str] = Field(None, max_length=10)
    type_code: Optional[str] = Field(None, max_length=10)
    ad_valorem: Optional[float] = None
    fixed_cost: Optional[float] = None
    unit_of_measure: Optional[str] = Field(None, max_length=10)
    description: Optional[str] = None


class USTariffFractionResponseDTO(BaseModel):
    """DTO para respuesta de fracción arancelaria americana"""

    model_config = ConfigDict(from_attributes=True)

    id: int
    code: str
    fraction: Optional[str] = None
    prefix: Optional[str] = None
    type_code: Optional[str] = None
    ad_valorem: Optional[float] = None
    fixed_cost: Optional[float] = None
    unit_of_measure: Optional[str] = None
    description: Optional[str] = None
    created_at: datetime
    updated_at: datetime

    @model_validator(mode="before")
    @classmethod
    def format_code_and_fraction(cls, data: Any) -> Any:
        # Check if data is an ORM model or dict
        if hasattr(data, "code"):
            raw_code = data.code
        elif isinstance(data, dict):
            raw_code = data.get("code")
        else:
            return data

        if raw_code:
            code_str = str(raw_code)
            fraction_raw = ""
            if isinstance(data, dict):
                fraction_raw = str(data.get("fraction") or "")
            else:
                fraction_raw = str(getattr(data, "fraction", "") or "")

            code = re.sub(r"[.\s-]", "", code_str)
            fraction = fraction_raw.strip() or code_str
            if "." not in fraction and "-" not in fraction:
                only_digits = re.sub(r"[.\s-]", "", fraction)
                if len(only_digits) == 10:
                    fraction = f"{only_digits[:4]}.{only_digits[4:6]}.{only_digits[6:8]}.{only_digits[8:]}"
                elif len(only_digits) == 8:
                    fraction = f"{only_digits[:4]}.{only_digits[4:6]}.{only_digits[6:]}"

            if isinstance(data, dict):
                data["code"] = code
                data["fraction"] = fraction
            else:
                # If it's an ORM object, we can't easily modify the object's attribute
                # cleanly without side effects for other things, so we convert it to dict
                new_data = {
                    c.name: getattr(data, c.name) for c in data.__table__.columns
                }
                new_data["code"] = code
                new_data["fraction"] = fraction
                return new_data

        return data
