"""Filter pump mode policy (on / off / auto daily window)."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import date, datetime, timedelta, timezone
from zoneinfo import ZoneInfo

from .config import ControlConfig
from .state import ControlState, FsmContext, PumpState


@dataclass
class FilterWindow:
    active: bool
    next_start_iso: str | None


def _local_tz(cfg: ControlConfig) -> ZoneInfo:
    if cfg.filter_auto.timezone == "local":
        return datetime.now().astimezone().tzinfo or ZoneInfo("UTC")  # type: ignore[return-value]
    return ZoneInfo(cfg.filter_auto.timezone)


def _parse_start_time(s: str) -> tuple[int, int]:
    parts = s.strip().split(":")
    if len(parts) != 2:
        raise ValueError(f"invalid start_time: {s!r}")
    return int(parts[0]), int(parts[1])


def window_for_day(
    cfg: ControlConfig,
    day: date,
    *,
    tz: ZoneInfo | None = None,
) -> tuple[datetime, datetime]:
    tz = tz or _local_tz(cfg)
    hour, minute = _parse_start_time(cfg.filter_auto.start_time)
    start = datetime(day.year, day.month, day.day, hour, minute, tzinfo=tz)
    end = start + timedelta(hours=cfg.filter_auto.run_time_hours)
    return start, end


def evaluate_filter_window(cfg: ControlConfig, now: datetime | None = None) -> FilterWindow:
    tz = _local_tz(cfg)
    now = now or datetime.now(tz)
    if now.tzinfo is None:
        now = now.replace(tzinfo=tz)
    else:
        now = now.astimezone(tz)

    start, end = window_for_day(cfg, now.date(), tz=tz)
    if start <= now < end:
        return FilterWindow(active=True, next_start_iso=None)

    if now < start:
        next_start = start
    else:
        next_day = now.date() + timedelta(days=1)
        next_start, _ = window_for_day(cfg, next_day, tz=tz)
    return FilterWindow(
        active=False,
        next_start_iso=next_start.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
    )


def desired_filter_pump(
    state: ControlState,
    cfg: ControlConfig,
    ctx: FsmContext,
    now: datetime | None = None,
) -> PumpState:
    mode = state.filter_mode
    if mode == "off":
        state.filter_window_active = False
        state.filter_next_start = None
        ctx.auto_run_started_mono = None
        return "off"
    if mode == "on":
        state.filter_window_active = False
        state.filter_next_start = None
        ctx.auto_run_started_mono = None
        return "on"

    win = evaluate_filter_window(cfg, now=now)
    state.filter_next_start = win.next_start_iso
    if not win.active:
        state.filter_window_active = False
        ctx.auto_run_started_mono = None
        return "off"

    state.filter_window_active = True
    return "on"
