"""Pydantic schemas for the Meter CRUD + swap declaration API (M7-T05).

Schema hierarchy
----------------
MeterResponse         — single meter row (id/label/commodity/started_at/ended_at/reason/note/created_at)
MeterListResponse     — ordered list of MeterResponse items
MeterDeclareRequest   — POST /api/energy/meters body (declare a swap or initial meter)
MeterPatchRequest     — PATCH /api/energy/meters/{id} body (all fields optional)
"""

from __future__ import annotations

from datetime import datetime
from enum import Enum

from pydantic import BaseModel, Field


# ---------------------------------------------------------------------------
# Enums
# ---------------------------------------------------------------------------


class MeterReason(str, Enum):
    """Allowed values for the meter epoch creation reason."""

    initial = "initial"
    meter_swap = "meter_swap"
    home_move = "home_move"
    other = "other"


# ---------------------------------------------------------------------------
# Response schemas
# ---------------------------------------------------------------------------


class MeterResponse(BaseModel):
    """Response schema for a single Meter epoch row.

    ``ended_at`` is ``null`` for the currently active meter.
    """

    id: int
    label: str
    commodity: str
    started_at: datetime
    ended_at: datetime | None
    reason: str
    note: str | None
    created_at: datetime

    model_config = {"from_attributes": True}


class MeterListResponse(BaseModel):
    """Response schema for GET /api/energy/meters.

    Meters are returned in ascending ``started_at`` order so the caller sees
    the historical installation sequence.
    """

    items: list[MeterResponse]
    total: int


# ---------------------------------------------------------------------------
# Request schemas
# ---------------------------------------------------------------------------

_VALID_REASONS = ", ".join(r.value for r in MeterReason)


class MeterDeclareRequest(BaseModel):
    """Request body for POST /api/energy/meters.

    Declares a new meter epoch (swap, home move, or initial declaration).  The
    service layer closes the current active meter for the given commodity at
    ``started_at`` and opens a new one.

    ``started_at`` follows the Principle-A localisation convention: a
    timezone-naive value is interpreted as the **server's local wall-clock time**
    (e.g. CEST midnight → stored as UTC the night before); a timezone-aware
    value is converted to UTC as-is.  Omitting ``started_at`` is not allowed —
    every meter declaration must carry an explicit start timestamp.

    ``commodity`` defaults to ``"electricity"``; the field is available for
    future use with ``gas`` or ``heating``.
    """

    label: str = Field(..., min_length=1, max_length=255)
    started_at: datetime = Field(
        ...,
        description=(
            "UTC (or server-local naive) datetime from which this meter epoch starts.  "
            "May be in the past (retroactive declaration)."
        ),
    )
    reason: MeterReason = Field(
        ...,
        description=f"Why this epoch was created.  One of: {_VALID_REASONS}.",
    )
    note: str | None = Field(default=None, max_length=1024)
    commodity: str = Field(
        default="electricity",
        min_length=1,
        max_length=32,
        description="Energy commodity this meter measures.  Defaults to 'electricity'.",
    )


class MeterPatchRequest(BaseModel):
    """Request body for PATCH /api/energy/meters/{id}.

    All fields are optional.  Only non-``None`` values are applied.

    Updating ``started_at`` is a **retroactive correction**: the service layer
    maintains timeline continuity (adjusting the preceding meter's ``ended_at``)
    and the API layer triggers ``recompute_range`` over the affected window so
    that billing attribution is re-judged.
    """

    label: str | None = Field(default=None, min_length=1, max_length=255)
    note: str | None = Field(default=None, max_length=1024)
    started_at: datetime | None = Field(
        default=None,
        description=(
            "Retroactive correction of the meter epoch start timestamp.  "
            "Triggers billing recompute over the affected window."
        ),
    )
