"""Pydantic schemas for calculation workflows."""

from __future__ import annotations

from typing import List, Optional

from pydantic import BaseModel, Field, PositiveFloat, ValidationError, field_validator

from services.pricing import PricingResult


class ImpurityInput(BaseModel):
    """Impurity configuration row supplied by the client."""

    name: str = Field(..., min_length=1)
    value: float | None = Field(None, ge=0)
    threshold: float | None = Field(None, ge=0)
    penalty: float | None = Field(None)

    @field_validator("name")
    @classmethod
    def _normalise_name(cls, value: str) -> str:
        return value.strip()


class ProfitabilityCalculationRequest(BaseModel):
    """Request payload for profitability calculations."""

    metal: str = Field(..., min_length=1)
    ore_tonnage: PositiveFloat
    head_grade_pct: float = Field(..., gt=0, le=100)
    recovery_pct: float = Field(..., gt=0, le=100)
    payable_pct: float | None = Field(None, gt=0, le=100)
    reference_price: PositiveFloat
    treatment_charge: float = Field(0, ge=0)
    smelting_charge: float = Field(0, ge=0)
    moisture_pct: float = Field(0, ge=0, le=100)
    moisture_threshold_pct: float | None = Field(None, ge=0, le=100)
    moisture_penalty_per_pct: float | None = None
    premiums: float = Field(0)
    fx_rate: PositiveFloat = Field(1)
    currency_code: str | None = Field(None, min_length=3, max_length=3)
    processing_opex: float = Field(0, ge=0)
    sustaining_capex: float = Field(0, ge=0)
    initial_capex: float = Field(0, ge=0)
    discount_rate: float | None = Field(None, ge=0, le=100)
    periods: int = Field(10, ge=1, le=120)
    impurities: List[ImpurityInput] = Field(default_factory=list)

    @field_validator("currency_code")
    @classmethod
    def _uppercase_currency(cls, value: str | None) -> str | None:
        if value is None:
            return None
        return value.strip().upper()

    @field_validator("metal")
    @classmethod
    def _normalise_metal(cls, value: str) -> str:
        return value.strip().lower()


class ProfitabilityCosts(BaseModel):
    """Aggregated cost components for profitability output."""

    processing_opex_total: float
    sustaining_capex_total: float
    initial_capex: float


class ProfitabilityMetrics(BaseModel):
    """Financial KPIs yielded by the profitability calculation."""

    npv: float | None
    irr: float | None
    payback_period: float | None
    margin: float | None


class CashFlowEntry(BaseModel):
    """Normalized cash flow row for reporting and charting."""

    period: int
    revenue: float
    processing_opex: float
    sustaining_capex: float
    net: float


class ProfitabilityCalculationResult(BaseModel):
    """Response body summarizing profitability calculation outputs."""

    pricing: PricingResult
    costs: ProfitabilityCosts
    metrics: ProfitabilityMetrics
    cash_flows: list[CashFlowEntry]
    currency: str | None


__all__ = [
    "ImpurityInput",
    "ProfitabilityCalculationRequest",
    "ProfitabilityCosts",
    "ProfitabilityMetrics",
    "CashFlowEntry",
    "ProfitabilityCalculationResult",
    "ValidationError",
]
