from typing import Optional

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

_HEX_COLOR = r"^#[0-9A-Fa-f]{6}$"


class CreateSectionRequest(BaseModel):
    model_config = ConfigDict(extra="forbid")

    code: str = Field(..., min_length=1, max_length=10)
    name: str = Field(..., min_length=1, max_length=100)
    description: Optional[str] = None
    is_religious: bool = False
    religious_denomination: Optional[str] = None

    # Cemetery-map fields (INDL-49)
    boundary: Optional[dict] = None  # GeoJSON Polygon
    display_color: Optional[str] = Field(default=None, pattern=_HEX_COLOR)
    plot_number_prefix: Optional[str] = Field(default=None, max_length=10)

    @field_validator("name", "code")
    @classmethod
    def _strip(cls, v: str) -> str:
        return v.strip()


class UpdateSectionRequest(BaseModel):
    model_config = ConfigDict(extra="forbid")

    name: Optional[str] = Field(default=None, min_length=1, max_length=100)
    description: Optional[str] = None
    is_religious: Optional[bool] = None
    religious_denomination: Optional[str] = None

    # Cemetery-map fields (INDL-49). `boundary` explicitly set to null clears it.
    boundary: Optional[dict] = None
    display_color: Optional[str] = Field(default=None, pattern=_HEX_COLOR)
    plot_number_prefix: Optional[str] = Field(default=None, max_length=10)


class AutogenerateGridRequest(BaseModel):
    """Bulk grid-of-plots generation within a section (INDL-49, AC-08/AC-10)."""

    model_config = ConfigDict(extra="forbid")

    rows: int = Field(..., ge=1, le=100)
    columns: int = Field(..., ge=1, le=100)
    plot_width_m: float = Field(..., gt=0, le=999.99)
    plot_length_m: float = Field(..., gt=0, le=999.99)
    gap_m: float = Field(default=0.3, ge=0, le=10)
    orientation_deg: float = Field(default=0.0, ge=0, lt=360)

    # Grid anchor (south-west corner). Optional — falls back to the section's
    # centroid, then the account centroid, server-side.
    origin_lat: Optional[float] = Field(default=None, ge=-90, le=90)
    origin_lng: Optional[float] = Field(default=None, ge=-180, le=180)

    # INDL-55 E-07 / AC-16a: dry-run capacity check. When true the server creates
    # nothing and returns how many plots fit in the section at this plot/spacing
    # size (max_plots_fit) so the UI can warn before the admin confirms.
    preview: bool = False

    @model_validator(mode="after")
    def _check_total(self):
        if self.rows * self.columns > 2000:
            raise ValueError("Grid is too large — split into multiple generations")
        return self
