"""Behavioral regression for Hermes-managed Python provenance on Windows."""

from __future__ import annotations

import json
import os
from pathlib import Path
import shutil
import subprocess

import pytest

from tests.install_ps1_fake_uv import compile_fake_uv


pytestmark = pytest.mark.windows_only

_INSTALL_PS1 = Path(__file__).resolve().parents[1] / "scripts" / "install.ps1"


def test_fresh_install_manifest_orders_repo_before_checkout_scoped_python(
    tmp_path: Path,
) -> None:
    powershell = shutil.which("powershell")
    if not powershell:
        pytest.skip("Windows PowerShell is required")

    install_dir = tmp_path / "install"
    run = subprocess.run(
        [
            powershell,
            "-NoProfile",
            "-ExecutionPolicy",
            "Bypass",
            "-File",
            str(_INSTALL_PS1),
            "-Manifest",
            "-HermesHome",
            str(tmp_path / "hermes-home"),
            "-InstallDir",
            str(install_dir),
        ],
        cwd=tmp_path,
        capture_output=True,
        text=True,
        check=False,
        timeout=45,
    )

    assert run.returncode == 0, run.stdout + run.stderr
    manifest = json.loads(run.stdout)
    stages = [stage["name"] for stage in manifest["stages"]]
    assert (
        stages.index("repository")
        < stages.index("python")
        < stages.index("venv")
    )
    assert not install_dir.exists(), "manifest lookup must remain read-only"


def _run_venv_stage(
    powershell: str,
    tmp_path: Path,
    hermes_home: Path,
    install_dir: Path,
    env: dict[str, str],
) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        [
            powershell,
            "-NoProfile",
            "-ExecutionPolicy",
            "Bypass",
            "-File",
            str(_INSTALL_PS1),
            "-Stage",
            "venv",
            "-HermesHome",
            str(hermes_home),
            "-InstallDir",
            str(install_dir),
        ],
        cwd=tmp_path,
        env=env,
        capture_output=True,
        text=True,
        check=False,
        timeout=45,
    )


def test_venv_stage_rejects_third_party_python_and_uses_managed_path(
    tmp_path: Path,
) -> None:
    powershell = shutil.which("powershell")
    if not powershell:
        pytest.skip("Windows PowerShell is required")

    hermes_home = tmp_path / "hermes-home"
    install_dir = tmp_path / "install"
    managed_root = install_dir / ".hermes-runtime" / "python"
    managed_python = managed_root / "cpython-3.11" / "python.exe"
    third_party = tmp_path / "KiCad" / "bin" / "python.exe"
    log = tmp_path / "uv.log"
    uv = hermes_home / "bin" / "uv.exe"
    uv.parent.mkdir(parents=True)
    install_dir.mkdir()
    managed_python.parent.mkdir(parents=True)
    third_party.parent.mkdir(parents=True)
    third_party.write_text("fake", encoding="ascii")
    compile_fake_uv(powershell, uv)
    shutil.copy2(uv, managed_python)

    env = {
        **os.environ,
        "FAKE_UV_LOG": str(log),
        "FAKE_MANAGED_PYTHON": str(managed_python),
        "FAKE_THIRD_PARTY_PYTHON": str(third_party),
        "UV_PYTHON": str(third_party),
        "UV_NO_MANAGED_PYTHON": "1",
        "UV_SYSTEM_PYTHON": "1",
    }
    run = _run_venv_stage(powershell, tmp_path, hermes_home, install_dir, env)
    installer_stdout = run.stdout
    installer_stderr = run.stderr
    frames = [
        json.loads(line) for line in installer_stdout.splitlines() if line.startswith("{")
    ]
    assert run.returncode == 0, installer_stdout + installer_stderr
    assert frames[-1]["ok"] is True
    commands = log.read_text(encoding="utf-8").splitlines()
    assert any(
        command.startswith("python find 3.11") and "--managed-python" in command
        for command in commands
    )
    venv_command = next(command for command in commands if command.startswith("venv venv"))
    assert f"--python {managed_python}" in venv_command
    assert "--managed-python" in venv_command
    assert "--no-python-downloads" in venv_command


def test_fallback_minor_is_reported_from_resolved_managed_interpreter(
    tmp_path: Path,
) -> None:
    powershell = shutil.which("powershell")
    if not powershell:
        pytest.skip("Windows PowerShell is required")

    hermes_home = tmp_path / "hermes-home"
    install_dir = tmp_path / "install"
    managed_python = (
        install_dir / ".hermes-runtime" / "python" / "cpython-3.12" / "python.exe"
    )
    uv = hermes_home / "bin" / "uv.exe"
    uv.parent.mkdir(parents=True)
    managed_python.parent.mkdir(parents=True)
    install_dir.mkdir(exist_ok=True)
    compile_fake_uv(powershell, uv)
    shutil.copy2(uv, managed_python)
    env = {
        **os.environ,
        "FAKE_UV_LOG": str(tmp_path / "uv.log"),
        "FAKE_MANAGED_PYTHON": str(managed_python),
        "FAKE_MANAGED_PYTHON_VERSION": "3.12",
        "FAKE_PYTHON_VERSION": "Python 3.12.13",
    }

    run = _run_venv_stage(powershell, tmp_path, hermes_home, install_dir, env)

    assert run.returncode == 0, run.stdout + run.stderr
    assert "Creating virtual environment with Python 3.12" in run.stdout
    assert "Virtual environment ready (Python 3.12)" in run.stdout
    created_python = install_dir / "venv" / "Scripts" / "python.exe"
    version = subprocess.run(
        [str(created_python), "--version"],
        env=env,
        capture_output=True,
        text=True,
        check=True,
    )
    assert version.stdout.strip() == "Python 3.12.13"


def test_python_find_drains_large_stderr_without_deadlock(tmp_path: Path) -> None:
    powershell = shutil.which("powershell")
    if not powershell:
        pytest.skip("Windows PowerShell is required")

    hermes_home = tmp_path / "hermes-home"
    install_dir = tmp_path / "install"
    managed_python = (
        install_dir / ".hermes-runtime" / "python" / "cpython-3.11" / "python.exe"
    )
    uv = hermes_home / "bin" / "uv.exe"
    uv.parent.mkdir(parents=True)
    managed_python.parent.mkdir(parents=True)
    compile_fake_uv(powershell, uv)
    shutil.copy2(uv, managed_python)
    env = {
        **os.environ,
        "FAKE_UV_LOG": str(tmp_path / "uv.log"),
        "FAKE_MANAGED_PYTHON": str(managed_python),
        "FAKE_UV_FIND_STDERR_BYTES": str(1024 * 1024),
    }

    run = _run_venv_stage(powershell, tmp_path, hermes_home, install_dir, env)

    assert run.returncode == 0, run.stdout + run.stderr
    assert "Creating virtual environment with Python 3.11" in run.stdout


def test_python_find_timeout_kills_uv_and_fails_stage(tmp_path: Path) -> None:
    powershell = shutil.which("powershell")
    if not powershell:
        pytest.skip("Windows PowerShell is required")

    hermes_home = tmp_path / "hermes-home"
    install_dir = tmp_path / "install"
    uv = hermes_home / "bin" / "uv.exe"
    uv.parent.mkdir(parents=True)
    install_dir.mkdir()
    compile_fake_uv(powershell, uv)
    env = {
        **os.environ,
        "FAKE_UV_LOG": str(tmp_path / "uv.log"),
        "FAKE_UV_FIND_DELAY_MS": "60000",
    }

    run = _run_venv_stage(powershell, tmp_path, hermes_home, install_dir, env)

    assert run.returncode != 0
    assert "uv python find 3.11 timed out after 30000 ms" in (run.stdout + run.stderr)


def test_venv_failure_fails_stage_and_restores_existing_environment(
    tmp_path: Path,
) -> None:
    powershell = shutil.which("powershell")
    if not powershell:
        pytest.skip("Windows PowerShell is required")

    hermes_home = tmp_path / "hermes-home"
    install_dir = tmp_path / "install"
    managed_python = (
        install_dir / ".hermes-runtime" / "python" / "cpython-3.11" / "python.exe"
    )
    old_python = install_dir / "venv" / "Scripts" / "python.exe"
    uv = hermes_home / "bin" / "uv.exe"
    for directory in (uv.parent, managed_python.parent, old_python.parent):
        directory.mkdir(parents=True, exist_ok=True)
    old_python.write_text("previous environment", encoding="ascii")
    compile_fake_uv(powershell, uv)
    shutil.copy2(uv, managed_python)
    env = {
        **os.environ,
        "FAKE_UV_LOG": str(tmp_path / "uv.log"),
        "FAKE_MANAGED_PYTHON": str(managed_python),
        "FAKE_UV_VENV_EXIT": "37",
    }

    run = _run_venv_stage(powershell, tmp_path, hermes_home, install_dir, env)

    assert run.returncode != 0
    assert "Failed to create virtual environment (uv venv exited with 37)" in (
        run.stdout + run.stderr
    )
    assert old_python.read_text(encoding="ascii") == "previous environment"
    frames = [json.loads(line) for line in run.stdout.splitlines() if line.startswith("{")]
    assert frames[-1]["ok"] is False
