# FILE: src/apps/plots/models/plot.py
from __future__ import annotations

from datetime import datetime
from decimal import Decimal
from typing import TYPE_CHECKING, Optional
from uuid import UUID

from geoalchemy2 import Geography
from sqlalchemy import (
    Boolean,
    DateTime,
    ForeignKey,
    Numeric,
    String,
    Text,
    UniqueConstraint,
)
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from src.database.base import TenantModel

if TYPE_CHECKING:
    from src.apps.records.models.record import Record
    from src.apps.plots.models.plot_type import PlotType
    from src.apps.sections.models.section import Section


class Plot(TenantModel):
    __tablename__ = "plots"

    __table_args__ = (
        UniqueConstraint("tenant_id", "plot_ref", name="uq_plots_tenant_ref"),
    )

    # Override tenant_id with explicit FK
    tenant_id: Mapped[UUID] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("accounts.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )

    plot_ref: Mapped[str] = mapped_column(String(50), nullable=False)
    section_id: Mapped[Optional[UUID]] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("sections.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )
    plot_type_id: Mapped[Optional[UUID]] = mapped_column(
        PG_UUID(as_uuid=True),
        ForeignKey("plot_types.id", ondelete="SET NULL"),
        nullable=True,
        index=True,
    )
    status: Mapped[str] = mapped_column(
        String(20), default="vacant", nullable=False, index=True
    )
    latitude: Mapped[Optional[float]] = mapped_column(Numeric(10, 7), nullable=True)
    longitude: Mapped[Optional[float]] = mapped_column(Numeric(10, 7), nullable=True)
    price_override: Mapped[Optional[float]] = mapped_column(
        Numeric(10, 2), nullable=True
    )
    notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    # Public-facing listing blurb shown on the availability page (INDL-42, AC-08).
    # Distinct from `notes` (staff-only). Capped at 180 chars at the schema layer.
    public_description: Mapped[Optional[str]] = mapped_column(String(180), nullable=True)
    is_veteran_section: Mapped[bool] = mapped_column(
        Boolean, default=False, nullable=False
    )

    # ── Cemetery map geometry (INDL-49 bulk grid writer / shared with INDL-41) ──
    geometry: Mapped[Optional[object]] = mapped_column(
        Geography(geometry_type="POLYGON", srid=4326), nullable=True
    )
    centroid: Mapped[Optional[object]] = mapped_column(
        Geography(geometry_type="POINT", srid=4326), nullable=True
    )
    rotation_deg: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2), nullable=True)

    # ── Detail-panel fields (INDL-41) ───────────────────────────────────────────
    # "Reserved by" / "Reserved on" surfaced in the plot detail panel (AC-13).
    reserved_by: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    reserved_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    # Optional display override; when set, shown instead of plot_ref everywhere
    # (map, list, detail, search) without consuming the section's next_plot_seq (AC-25).
    label_manual: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)

    # Relationships
    section: Mapped[Optional["Section"]] = relationship(
        "Section", back_populates="plots"
    )
    plot_type: Mapped[Optional["PlotType"]] = relationship(
        "PlotType", back_populates="plots"
    )
    record: Mapped[Optional["Record"]] = relationship(
        "Record", uselist=False, back_populates="plot"
    )
