"""LIVE Windows E2E for plan-reconciliation (#92902) on windows-latest.

Real processes with real Hermes-shaped argv, real inventory collection
(PID-file discovery + supervisor detection on REAL Windows), real
reconciliation. No mocks on the components under test.

 1. Spawn a real process registered as a profile gateway (PID file + state
    file in a temp HERMES_HOME) — real collect_runtime_inventory() must find
    it, classify supervisor=manual, mechanism id 'manual'.
 2. Reconcile with bookkeeping that MISSES it -> unaccounted + escalation.
 3. Reconcile with it in killed_pids -> 'stopped', no escalation.
 4. Machine-id contract holds on Windows (no display strings leak in).
"""
import io, contextlib, json, os, subprocess, sys, tempfile, time
from pathlib import Path

WORKTREE = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(WORKTREE))

import pytest

pytestmark = pytest.mark.skipif(sys.platform != "win32", reason="live Windows E2E")


def test_plan_reconciliation_live_windows(tmp_path, monkeypatch):
    home = tmp_path / ".hermes"
    home.mkdir()
    monkeypatch.setenv("HERMES_HOME", str(home))

    # Real live process standing in for a manual gateway
    child = subprocess.Popen(
        [sys.executable, "-c", "import time; time.sleep(120)"],
        stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
    )
    try:
        time.sleep(0.5)
        assert child.poll() is None

        import psutil

        create_time = psutil.Process(child.pid).create_time()
        (home / "gateway_state.json").write_text(json.dumps({
            "pid": child.pid,
            "create_time": create_time,
            "gateway_state": "running",
            "kind": "hermes-gateway",
            "code_sha": "f" * 40,
            "code_version": "0.20.5",
        }), encoding="utf-8")

        import hermes_cli.profiles as profiles_mod
        monkeypatch.setattr(profiles_mod, "_get_default_hermes_home", lambda: home)
        monkeypatch.setattr(profiles_mod, "_get_profiles_root", lambda: tmp_path / "none")

        from hermes_cli.update_inventory import (
            collect_runtime_inventory,
            match_runtime_outcomes,
            report_unaccounted_runtimes,
        )

        plan = collect_runtime_inventory()
        rows = [r for r in plan.runtimes if r.pid == child.pid]
        assert rows, f"real inventory missed the live process: {plan.runtimes}"
        rt = rows[0]
        assert rt.supervisor == "manual"
        assert rt.restart_via == "manual", "machine id, not display string"
        assert rt.code_sha == "f" * 40

        # 2. bookkeeping misses it -> unaccounted + escalation
        buf = io.StringIO()
        with contextlib.redirect_stdout(buf):
            outcomes = match_runtime_outcomes(
                plan, restarted_services=[], relaunched_profiles=[],
                externally_supervised_profiles=[], killed_pids=set(),
                failed_units=[],
            )
            escalated = report_unaccounted_runtimes(outcomes)
        mine = [o for o in outcomes if o["pid"] == child.pid]
        assert mine and mine[0]["outcome"] == "unaccounted"
        assert escalated is True
        assert "never touched" in buf.getvalue()

        # 3. accounted as stopped -> clean
        outcomes2 = match_runtime_outcomes(
            plan, restarted_services=[], relaunched_profiles=[],
            externally_supervised_profiles=[], killed_pids={child.pid},
            failed_units=[],
        )
        mine2 = [o for o in outcomes2 if o["pid"] == child.pid]
        assert mine2 and mine2[0]["outcome"] == "stopped"
        assert report_unaccounted_runtimes(outcomes2) is False
    finally:
        if child.poll() is None:
            child.kill()
        child.wait()
