from typing import Any

from pydantic import BaseModel, ConfigDict, Field, field_validator


class ExtractionMetadata(BaseModel):
    model: str = "stub"
    latency_ms: float = 0.0


class LineItem(BaseModel):
    model_config = ConfigDict(extra="allow")

    line_number: int | None = None
    item_code: str | None = None
    barcode: str | None = None
    item_name: str | None = None
    batch_number: str | None = None
    production: str | None = None
    blend: str | None = None
    grain_type: str | None = None
    variety_type: str | None = None
    process_type: str | None = None
    coo: str | None = None
    unit: str | None = None
    quantity: float | None = None
    quantity_mt: float | None = None
    unit_price: float | None = None
    amount: float | None = None
    vat_pct: float | None = None
    vat_amount: float | None = None
    amount_with_vat: float | None = None
    expiry_date: str | None = None
    total_bags: float | None = None
    total_mt: float | None = None
    shipment_no: str | None = None
    quality_report_no: str | None = None
    warehouse_bags: dict = Field(default_factory=dict)

    @field_validator(
        "item_code", "barcode", "item_name", "batch_number", "production",
        "blend", "grain_type", "variety_type", "process_type", "coo",
        "unit", "expiry_date", "shipment_no", "quality_report_no",
        mode="before",
    )
    @classmethod
    def empty_str_to_none(cls, v):
        if isinstance(v, str) and v.strip() in ("", "null", "N/A", "n/a", "-"):
            return None
        return v


class ExtractedFields(BaseModel):
    # Allow extra fields the model may return — stored as-is for future use
    model_config = ConfigDict(extra="allow")

    # Core fields
    document_type: str = "incoming_invoice"
    document_number: str | None = None
    warehouse_name: str | None = None
    item_code: str | None = None
    item_name: str | None = None
    batch_number: str | None = None
    expiry_date: str | None = None
    quantity_mt: float | None = None
    document_date: str | None = None
    reference_number: str | None = None

    # Additional fields
    supplier_name: str | None = None
    supplier_trn: str | None = None
    buyer_name: str | None = None
    buyer_trn: str | None = None
    due_date: str | None = None
    currency: str | None = None
    payment_terms: str | None = None
    total_amount: float | None = None
    vat_amount: float | None = None
    net_amount: float | None = None
    unit: str | None = None
    unit_price: float | None = None
    all_batches: str | None = None
    all_items: str | None = None

    # Line items array — every row from the document
    line_items: list[LineItem] = Field(default_factory=list)

    @field_validator(
        "document_number", "warehouse_name", "item_code", "item_name",
        "batch_number", "expiry_date", "document_date", "reference_number",
        "supplier_name", "supplier_trn", "buyer_name", "buyer_trn",
        "due_date", "currency", "payment_terms", "unit", "all_batches", "all_items",
        mode="before",
    )
    @classmethod
    def empty_str_to_none(cls, v):
        if isinstance(v, str) and v.strip() in ("", "null", "N/A", "n/a", "-"):
            return None
        return v

    @field_validator("quantity_mt", "total_amount", "vat_amount", "net_amount", "unit_price", mode="before")
    @classmethod
    def empty_num_to_none(cls, v):
        if v == "" or v is None:
            return None
        try:
            return float(str(v).replace(",", ""))
        except (ValueError, TypeError):
            return None


class ExtractionResponse(BaseModel):
    success: bool = True
    document_type: str
    extracted_fields: ExtractedFields
    validation_flags: list[str] = Field(default_factory=list)
    confidence: float = 0.0
    raw_model_output: Any
    metadata: ExtractionMetadata = Field(default_factory=ExtractionMetadata)
