"""Tests for `write_config` — TOML serialiser used by the first-run wizard.

The load-bearing invariant: write_config → load_config produces an equivalent
Config. If that holds, the wizard can write whatever the user picked and
trust the rest of the codebase to read it back the same way.
"""

from __future__ import annotations

from pathlib import Path

from openrun.config import (
    BanisterParams,
    Config,
    HRZones,
    UserProfile,
    load_config,
    write_config,
)


def _sample_config(tmp_path: Path) -> Config:
    return Config(
        user=UserProfile(
            name="Test Runner",
            height_cm=180.0,
            weight_kg=72.5,
            hr_max=200,
            lthr=178,
            resting_hr=48,
            zones=HRZones(
                z1=(100, 120), z2=(121, 140), z3=(141, 160),
                z4=(161, 180), z5=(181, 200),
            ),
        ),
        db_path=tmp_path / "data" / "garmin.db",
        banister=BanisterParams(ctl_tau_days=42.0, atl_tau_days=7.0, race_day_tl_per_km=7.0),
        races=(("wk 4 — 30K", "2026-06-13"), ("wk 17 — 50 mile", "2026-09-12")),
    )


def test_write_then_load_roundtrip(tmp_path: Path) -> None:
    cfg = _sample_config(tmp_path)
    out = tmp_path / "openrun.toml"
    write_config(cfg, out)

    loaded = load_config(out)
    assert loaded.user.name == cfg.user.name
    assert loaded.user.hr_max == cfg.user.hr_max
    assert loaded.user.lthr == cfg.user.lthr
    assert loaded.user.resting_hr == cfg.user.resting_hr
    assert loaded.user.weight_kg == cfg.user.weight_kg
    assert loaded.user.height_cm == cfg.user.height_cm
    assert loaded.user.zones == cfg.user.zones
    assert loaded.banister == cfg.banister
    assert loaded.races == cfg.races


def test_write_handles_missing_optional_fields(tmp_path: Path) -> None:
    """Height/weight/lthr/rhr are optional — omitted entirely from output."""
    cfg = Config(
        user=UserProfile(name="Minimal", hr_max=190),
        db_path=tmp_path / "minimal.db",
    )
    out = tmp_path / "openrun.toml"
    write_config(cfg, out)
    body = out.read_text()
    assert "height_cm" not in body
    assert "weight_kg" not in body
    assert "lthr" not in body
    assert "resting_hr" not in body

    loaded = load_config(out)
    assert loaded.user.hr_max == 190
    assert loaded.user.height_cm is None


def test_write_quotes_strings_with_special_chars(tmp_path: Path) -> None:
    """Race labels and athlete names commonly contain Unicode em-dashes and quotes;
    the serialiser must escape these so the file parses back."""
    cfg = Config(
        user=UserProfile(name='O\'Brien — "Speedy"', hr_max=200),
        db_path=tmp_path / "x.db",
        races=(('wk 17 — Cascade Crest "50M"', "2026-09-12"),),
    )
    out = tmp_path / "openrun.toml"
    write_config(cfg, out)
    loaded = load_config(out)
    assert loaded.user.name == 'O\'Brien — "Speedy"'
    assert loaded.races == (('wk 17 — Cascade Crest "50M"', "2026-09-12"),)


def test_write_creates_parent_dir(tmp_path: Path) -> None:
    cfg = Config(user=UserProfile(name="x", hr_max=200), db_path=tmp_path / "x.db")
    nested = tmp_path / "a" / "b" / "openrun.toml"
    write_config(cfg, nested)
    assert nested.exists()


def test_no_races_omits_section(tmp_path: Path) -> None:
    cfg = Config(user=UserProfile(name="x", hr_max=200), db_path=tmp_path / "x.db", races=())
    out = tmp_path / "openrun.toml"
    write_config(cfg, out)
    assert "[[races]]" not in out.read_text()
    assert load_config(out).races == ()
