"""Every update surface validates staged code before changing an active plugin."""
from __future__ import annotations

import subprocess

import pytest

from tests.hermes_cli.test_plugin_update_transaction import installed, _version  # noqa: F401
from tests.pm.test_plugin_survival_contract import admission_env  # noqa: F401


@pytest.mark.parametrize("installed", ["catalog", "custom"], indirect=True)
def test_cli_update_scan_refusal_keeps_the_installed_tree(installed, monkeypatch):
    from hermes_cli import plugins_cmd as pc

    _, home, repo, target, state = installed
    old = (target / "__init__.py").read_bytes()
    before = (home / "config.yaml").read_bytes()
    state["sha"] = _version(repo, "2.0.0")
    scans = []

    def refuse(staged, source, **kwargs):
        scans.append(staged)
        assert staged != target
        assert (target / "__init__.py").read_bytes() == old
        raise pc.PluginScanBlocked("fixture refuses candidate")

    monkeypatch.setattr(pc, "_scan_plugin_tree", refuse)
    with pytest.raises(SystemExit):
        pc.cmd_update("transactional", interactive=False)
    assert len(scans) == 1
    assert (target / "__init__.py").read_bytes() == old
    assert (home / "config.yaml").read_bytes() == before


@pytest.mark.parametrize("installed", ["catalog", "custom"], indirect=True)
def test_disabled_update_does_not_change_dependencies_or_enablement(installed, monkeypatch):
    from hermes_cli import plugins_cmd as pc
    from pm import paths

    _, home, repo, target, state = installed
    pc._set_plugin_enabled("transactional", enable=False)
    config = (home / "config.yaml").read_bytes()
    facts = paths.runtime_facts_path().read_bytes()
    state["sha"] = _version(repo, "2.0.0")
    monkeypatch.setattr("pm.packages.Venv.apply",
                        lambda *args, **kwargs: pytest.fail("disabled plugin changed the dependency selection"))
    result = pc.dashboard_update_user_plugin("transactional")
    assert result["ok"], result
    assert subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=target, text=True).strip() == state["sha"]
    assert (home / "config.yaml").read_bytes() == config
    assert paths.runtime_facts_path().read_bytes() == facts


@pytest.mark.parametrize("installed", ["catalog", "custom"], indirect=True)
def test_enablement_before_lock_acquisition_cannot_skip_validation(installed, monkeypatch):
    from contextlib import contextmanager
    from hermes_cli import plugins_cmd as pc, runtime_state
    from pm import paths

    _, home, repo, target, state = installed
    pc._set_plugin_enabled("transactional", enable=False)
    watched = [target / "__init__.py", target / "pyproject.toml", home / "plugins/.install-metadata.json"]
    before = {path: path.read_bytes() for path in watched}
    state["sha"] = _version(repo, "2.0.0", broken=True)
    lock = runtime_state.runtime_lock
    enabled = {}

    @contextmanager
    def enable_before_acquiring_lock(project, **kwargs):
        # The plugin becomes active after the update read its state but before PM's
        # publication holds the install lock; the enablement itself is a completed PM
        # transaction (its own lock cycle), so it runs outside this re-entered seam.
        if not enabled:
            enabled["begun"] = True
            monkeypatch.setattr(runtime_state, "runtime_lock", lock)
            pc._set_plugin_enabled("transactional", enable=True)
            monkeypatch.setattr(runtime_state, "runtime_lock", enable_before_acquiring_lock)
            enabled["config"] = (home / "config.yaml").read_bytes()
            enabled["facts"] = paths.runtime_facts_path().read_bytes()
        with lock(project, **kwargs):
            yield

    monkeypatch.setattr(runtime_state, "runtime_lock", enable_before_acquiring_lock)
    result = pc.dashboard_update_user_plugin("transactional")
    assert result["ok"] is False, result
    assert {path: path.read_bytes() for path in watched} == before
    assert (home / "config.yaml").read_bytes() == enabled["config"]
    assert paths.runtime_facts_path().read_bytes() == enabled["facts"]
