"""shared_metrics.status / shared_metrics.set: the Desktop consent path keeps the CLI wizard's
invariants (sending needs collection, every change reconciles the consent windows) and lands in the
profile the request names, never the launch profile."""

from __future__ import annotations

import sqlite3
from pathlib import Path

import hermes_yaml as yaml

from tui_gateway import server


def _bind_homes(monkeypatch, tmp_path: Path) -> tuple[Path, Path]:
    launch, worker = tmp_path / "launch", tmp_path / "profiles" / "code"
    for home in (launch, worker):
        home.mkdir(parents=True)
        (home / "config.yaml").write_text(yaml.safe_dump({"model": {"provider": "nous"}}), encoding="utf-8")
    monkeypatch.setattr(server, "_hermes_home", launch)
    monkeypatch.setenv("HERMES_HOME", str(launch))
    monkeypatch.setattr(server, "_profile_home", lambda name: worker if (name or "").strip() == "code" else None)
    server._cfg_cache = server._cfg_sig = server._cfg_path = None
    return launch, worker


def _call(method: str, params: dict) -> dict:
    return server._methods[method]("rid", params)["result"]


def _shared_metrics(home: Path) -> dict:
    cfg = yaml.safe_load((home / "config.yaml").read_text(encoding="utf-8")) or {}
    return (cfg.get("telemetry") or {}).get("shared_metrics") or {}


def _windows(home: Path) -> list[tuple]:
    db = home / "telemetry" / "shared_metrics" / "metrics.sqlite3"
    with sqlite3.connect(db) as conn:
        return conn.execute("SELECT opened_at, closed_at FROM send_consent_windows ORDER BY rowid").fetchall()


def test_send_without_collection_is_normalized_off_and_closes_the_consent_window(tmp_path, monkeypatch):
    launch, worker = _bind_homes(monkeypatch, tmp_path)

    assert _call("shared_metrics.set", {"profile": "code", "enabled": True, "send": True}) == {
        "enabled": True, "send": True, "decided": True, "reask": False}
    [(opened, closed)] = _windows(worker)
    assert opened and closed is None

    # send=true alone is refused: collection off withdraws send consent, in config AND in the store.
    assert _call("shared_metrics.set", {"profile": "code", "enabled": False, "send": True}) == {
        "enabled": False, "send": False, "decided": True, "reask": False}
    assert _shared_metrics(worker) == {"enabled": False, "send": False, "offer_version": 2}
    [(_, closed)] = _windows(worker)
    assert closed is not None

    assert _shared_metrics(launch) == {}
    assert not (launch / "telemetry").exists()


def test_status_is_undecided_until_a_key_is_written(tmp_path, monkeypatch):
    _launch, worker = _bind_homes(monkeypatch, tmp_path)

    unasked = {"enabled": False, "send": False, "decided": False, "reask": False}
    assert _call("shared_metrics.status", {"profile": "code"}) == unasked

    # A "No thanks" from before the type-ahead fix (no offer_version) may never have been seen:
    # it is offered once more, and the answer to that settles it.
    (worker / "config.yaml").write_text(
        yaml.safe_dump({"telemetry": {"shared_metrics": {"enabled": False}}}), encoding="utf-8")
    assert _call("shared_metrics.status", {"profile": "code"}) == {**unasked, "reask": True}
    _call("shared_metrics.set", {"profile": "code", "enabled": False, "send": False})
    assert _call("shared_metrics.status", {"profile": "code"}) == {**unasked, "decided": True}

    # A collect-only answer (no longer offered) from before the offer had versions stays decided.
    (worker / "config.yaml").write_text(
        yaml.safe_dump({"telemetry": {"shared_metrics": {"enabled": True, "send": False}}}), encoding="utf-8")
    assert _call("shared_metrics.status", {"profile": "code"}) == {
        "enabled": True, "send": False, "decided": True, "reask": False}


def test_only_the_first_run_answer_records_desktop_setup_completed(tmp_path, monkeypatch):
    _launch, _worker = _bind_homes(monkeypatch, tmp_path)
    import hermes_cli.observability.shared_metrics_events as events

    calls: list[dict] = []
    monkeypatch.setattr(events, "record_setup_completed", lambda **kw: calls.append(kw))

    _call("shared_metrics.set", {"profile": "code", "enabled": True, "send": False, "first_run": True})
    _call("shared_metrics.set", {"profile": "code", "enabled": True, "send": True})

    assert calls == [{"surface": "desktop", "provider": "nous"}]


def test_an_opt_out_purges_receipts_kept_for_a_later_start(tmp_path, monkeypatch):
    """A Desktop "No" must not leave an installer receipt or a parked update receipt for a later opt-in
    to count; only the named profile is touched."""
    launch, worker = _bind_homes(monkeypatch, tmp_path)
    kept = [worker / "telemetry" / "shared_metrics" / name for name in ("pending_installs", "pending_updates")]
    for directory in kept + [launch / "telemetry" / "shared_metrics" / "pending_installs"]:
        directory.mkdir(parents=True, exist_ok=True)
        (directory / f"{'a' * 32}.json").write_text("{}", encoding="utf-8")

    _call("shared_metrics.set", {"profile": "code", "enabled": True, "send": False})
    assert all(d.exists() for d in kept)
    _call("shared_metrics.set", {"profile": "code", "enabled": False, "send": False})
    assert not any(d.exists() for d in kept)
    assert (launch / "telemetry" / "shared_metrics" / "pending_installs").exists()
