"""Load control daemon configuration."""

from __future__ import annotations

import json
from dataclasses import dataclass, field
from pathlib import Path


@dataclass
class GpioConfig:
    heat_pump: int = 22
    filter_pump: int = 23
    active_high: bool = True


@dataclass
class MaintainConfig:
    band_f: float = 5.0
    startup_delay_s: float = 20.0
    hot_in_rise_f: float = 10.0
    startup_attempts: int = 3
    retry_off_s: float = 5.0


@dataclass
class BackflushConfig:
    duration_s: float = 10.0
    revert_to_heat_mode: str = "sleep"


@dataclass
class FilterAutoConfig:
    start_time: str = "00:00"
    run_time_hours: float = 2.0
    timezone: str = "local"


@dataclass
class ControlConfig:
    redis_url: str = "redis://127.0.0.1:6379/0"
    log_path: Path = Path("/var/log/hot-tub/control.log")
    state_path: Path = Path("/var/lib/hot-tub/control-state.json")
    gpio: GpioConfig = field(default_factory=GpioConfig)
    maintain: MaintainConfig = field(default_factory=MaintainConfig)
    backflush: BackflushConfig = field(default_factory=BackflushConfig)
    filter_auto: FilterAutoConfig = field(default_factory=FilterAutoConfig)
    target_f_default: float = 102.0
    target_f_min: float = 50.0
    target_f_max: float = 110.0
    temps_stale_s: float = 15.0
    loop_interval_s: float = 1.0
    heartbeat_s: float = 5.0


def _merge_gpio(data: dict) -> GpioConfig:
    g = GpioConfig()
    block = data.get("gpio") or {}
    if "heat_pump" in block:
        g.heat_pump = int(block["heat_pump"])
    if "filter_pump" in block:
        g.filter_pump = int(block["filter_pump"])
    if "active_high" in block:
        g.active_high = bool(block["active_high"])
    return g


def _merge_maintain(data: dict) -> MaintainConfig:
    m = MaintainConfig()
    block = data.get("maintain") or {}
    for key, typ in (
        ("band_f", float),
        ("startup_delay_s", float),
        ("hot_in_rise_f", float),
        ("startup_attempts", int),
        ("retry_off_s", float),
    ):
        if key in block:
            setattr(m, key, typ(block[key]))
    return m


def _merge_backflush(data: dict) -> BackflushConfig:
    b = BackflushConfig()
    block = data.get("backflush") or {}
    if "duration_s" in block:
        b.duration_s = float(block["duration_s"])
    if "revert_to_heat_mode" in block:
        b.revert_to_heat_mode = str(block["revert_to_heat_mode"])
    return b


def _merge_filter_auto(data: dict) -> FilterAutoConfig:
    f = FilterAutoConfig()
    block = data.get("filter_auto") or {}
    if "start_time" in block:
        f.start_time = str(block["start_time"])
    if "run_time_hours" in block:
        f.run_time_hours = float(block["run_time_hours"])
    if "timezone" in block:
        f.timezone = str(block["timezone"])
    return f


def load_config(path: Path | None) -> ControlConfig:
    cfg = ControlConfig()
    if path is None or not path.exists():
        return cfg
    data = json.loads(path.read_text())
    if "redis_url" in data:
        cfg.redis_url = str(data["redis_url"])
    if "log_path" in data:
        cfg.log_path = Path(data["log_path"])
    if "state_path" in data:
        cfg.state_path = Path(data["state_path"])
    cfg.gpio = _merge_gpio(data)
    cfg.maintain = _merge_maintain(data)
    cfg.backflush = _merge_backflush(data)
    cfg.filter_auto = _merge_filter_auto(data)
    if "target_f_default" in data:
        cfg.target_f_default = float(data["target_f_default"])
    if "target_f_min" in data:
        cfg.target_f_min = float(data["target_f_min"])
    if "target_f_max" in data:
        cfg.target_f_max = float(data["target_f_max"])
    if "temps_stale_s" in data:
        cfg.temps_stale_s = float(data["temps_stale_s"])
    if "loop_interval_s" in data:
        cfg.loop_interval_s = float(data["loop_interval_s"])
    if "heartbeat_s" in data:
        cfg.heartbeat_s = float(data["heartbeat_s"])
    return cfg
