"""
Input schema for the /analyze endpoint.

This is the single most important validation surface in the system —
every downstream model depends on this data being clean. We validate
aggressively here so bad input never reaches a model and produces a
silently wrong prediction.

Design choice: crop/district lookups are loaded from data/lookup/*.json
at startup (see app/services/reference_data.py) rather than hardcoded
here, so the client coordinator can update supported crops/districts
without a code change and redeploy.
"""

from typing import Union

from pydantic import BaseModel, Field, field_validator, model_validator

MONTH_NAME_TO_NUMBER = {
    "january": 1, "jan": 1,
    "february": 2, "feb": 2,
    "march": 3, "mar": 3,
    "april": 4, "apr": 4,
    "may": 5,
    "june": 6, "jun": 6,
    "july": 7, "jul": 7,
    "august": 8, "aug": 8,
    "september": 9, "sep": 9, "sept": 9,
    "october": 10, "oct": 10,
    "november": 11, "nov": 11,
    "december": 12, "dec": 12,
}


class CropAnalysisRequest(BaseModel):
    crop: str = Field(..., min_length=2, max_length=50, examples=["rice"])
    location: str = Field(..., min_length=2, max_length=100, examples=["Thanjavur"])
    month: Union[str, int] = Field(..., examples=["June", 6])
    crop_plan_id: str | None = Field(
        None,
        description="Optional ID of a saved CropPlan this analysis belongs to "
                    "(SaaS dashboard use). Omit for one-off / API-key-based calls.",
    )

    @field_validator("crop", "location")
    @classmethod
    def strip_and_lowercase(cls, v: str) -> str:
        cleaned = v.strip().lower()
        if not cleaned:
            raise ValueError("Field cannot be empty or whitespace only")
        return cleaned

    @field_validator("month")
    @classmethod
    def normalize_month(cls, v: Union[str, int]) -> int:
        if isinstance(v, int):
            if not 1 <= v <= 12:
                raise ValueError("Month must be between 1 and 12")
            return v
        if isinstance(v, str):
            key = v.strip().lower()
            if key.isdigit():
                num = int(key)
                if not 1 <= num <= 12:
                    raise ValueError("Month must be between 1 and 12")
                return num
            if key not in MONTH_NAME_TO_NUMBER:
                raise ValueError(
                    f"'{v}' is not a recognized month name. "
                    f"Use a full or short English month name, or a number 1-12."
                )
            return MONTH_NAME_TO_NUMBER[key]
        raise ValueError("Month must be a string or integer")

    @model_validator(mode="after")
    def validate_combination(self) -> "CropAnalysisRequest":
        # Cross-field validation hook. Reserved for rules like
        # "crop X is never grown in district Y" once that lookup table
        # exists — kept here so the check lives next to the schema,
        # not buried in a service file.
        return self


class TaskSubmissionResponse(BaseModel):
    """Returned immediately by POST /analyze — the job is queued, not done yet."""
    task_id: str
    status: str = "queued"
    poll_url: str


class TaskStatusResponse(BaseModel):
    task_id: str
    status: str  # queued | running | completed | failed
    result: dict | None = None
    error: str | None = None
