from __future__ import annotations

from datetime import date, datetime

from pydantic import BaseModel, ConfigDict, field_validator, model_validator

from models import ResourceType, ScenarioStatus
from services.currency import CurrencyValidationError, normalise_currency


class ScenarioBase(BaseModel):
    name: str
    description: str | None = None
    status: ScenarioStatus = ScenarioStatus.DRAFT
    start_date: date | None = None
    end_date: date | None = None
    discount_rate: float | None = None
    currency: str | None = None
    primary_resource: ResourceType | None = None

    model_config = ConfigDict(extra="forbid")

    @field_validator("currency")
    @classmethod
    def normalise_currency(cls, value: str | None) -> str | None:
        if value is None:
            return None
        candidate = value if isinstance(value, str) else str(value)
        candidate = candidate.strip()
        if not candidate:
            return None
        try:
            return normalise_currency(candidate)
        except CurrencyValidationError as exc:
            raise ValueError(str(exc)) from exc


class ScenarioCreate(ScenarioBase):
    pass


class ScenarioUpdate(BaseModel):
    name: str | None = None
    description: str | None = None
    status: ScenarioStatus | None = None
    start_date: date | None = None
    end_date: date | None = None
    discount_rate: float | None = None
    currency: str | None = None
    primary_resource: ResourceType | None = None

    model_config = ConfigDict(extra="forbid")

    @field_validator("currency")
    @classmethod
    def normalise_currency(cls, value: str | None) -> str | None:
        if value is None:
            return None
        candidate = value if isinstance(value, str) else str(value)
        candidate = candidate.strip()
        if not candidate:
            return None
        try:
            return normalise_currency(candidate)
        except CurrencyValidationError as exc:
            raise ValueError(str(exc)) from exc


class ScenarioRead(ScenarioBase):
    id: int
    project_id: int
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class ScenarioComparisonRequest(BaseModel):
    scenario_ids: list[int]

    model_config = ConfigDict(extra="forbid")

    @model_validator(mode="after")
    def ensure_minimum_ids(self) -> "ScenarioComparisonRequest":
        unique_ids: list[int] = list(dict.fromkeys(self.scenario_ids))
        if len(unique_ids) < 2:
            raise ValueError(
                "At least two unique scenario identifiers are required for comparison.")
        self.scenario_ids = unique_ids
        return self


class ScenarioComparisonResponse(BaseModel):
    project_id: int
    scenarios: list[ScenarioRead]

    model_config = ConfigDict(from_attributes=True)
