"""Data deletion respects declared runtime ownership, confirmation and scope."""
from __future__ import annotations

from pathlib import Path
from types import SimpleNamespace

import pytest

import hermes_cli.uninstall as uninstall


@pytest.fixture
def layout(tmp_path, monkeypatch):
    user = tmp_path / "user"
    user.mkdir()
    home = user / "hermes-data"
    source = home / "workspace" / "custom-source"
    store = home / "machine" / "tool-store"
    userdata = user / "desktop-data"
    witnesses = [source / "hermes_cli" / "__init__.py", store / "python" / "python.exe",
                 home / "installs" / "other-install" / "facts.json", home / "bin" / "hermes.cmd",
                 home / "profiles" / "sibling" / "config.yaml",
                 home / "cache" / "partials" / ".locks" / "other-profile-transfer"]
    for path in witnesses:
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text("keep", encoding="utf-8")
    data = [home / "config.yaml", home / "sessions" / "session.json", home / "workspace" / "notes.txt",
            home / ".env", home / "logs" / "file"]
    for path in data:
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text("{}" if path.suffix in {".yaml", ".json"} else "user data", encoding="utf-8")
    monkeypatch.setattr(Path, "home", lambda: user)
    monkeypatch.setenv("HERMES_HOME", str(home))
    monkeypatch.setenv("HERMES_RUNTIME_DIR", str(store))
    monkeypatch.setattr(uninstall, "get_project_root", lambda: source)
    monkeypatch.setattr(uninstall, "get_hermes_home", lambda: home)
    monkeypatch.setattr("hermes_cli.gui_uninstall.desktop_userdata_dir", lambda: userdata)
    return home, witnesses, data


@pytest.mark.parametrize("mode", ["confirmed", "cancel", "dry-run"])
def test_data_only_preserves_runtime_and_sibling_homes(layout, monkeypatch, mode):
    import json
    from pm.environments import install_state_dir, runtime_facts_path, selected_venv

    monkeypatch.delattr(Path, "is_junction", raising=False)
    home, witnesses, data = layout
    source = uninstall.get_project_root()
    generation = install_state_dir(source) / "environments" / "selected"
    generation.mkdir(parents=True)
    (generation / "pyvenv.cfg").write_text("include-system-site-packages = false", encoding="utf-8")
    runtime_facts_path(source).write_text(json.dumps({"packages": {"venv": {"environment": str(generation)}}}), encoding="utf-8")
    monkeypatch.setattr("builtins.input", lambda *args: "no")
    uninstall.run_data_uninstall(SimpleNamespace(yes=mode != "cancel", dry_run=mode == "dry-run"))
    assert selected_venv(source) == generation
    assert all(path.read_text(encoding="utf-8") == "keep" for path in witnesses)
    assert all(path.exists() is (mode != "confirmed") for path in data)
    assert home.is_dir()


def test_data_only_reports_a_failed_removal(layout, monkeypatch, capsys):
    home, witnesses, _ = layout
    real = uninstall.shutil.rmtree

    def refuse(path, *args, **kwargs):
        if Path(path) == home / "sessions":
            raise PermissionError("fixture holds sessions")
        return real(path, *args, **kwargs)

    monkeypatch.setattr(uninstall.shutil, "rmtree", refuse)
    with pytest.raises(SystemExit) as failure:
        uninstall.run_data_uninstall(SimpleNamespace(yes=True, dry_run=False))
    assert failure.value.code != 0
    output = capsys.readouterr().out
    assert "Hermes data removed" not in output
    assert str(home / "sessions") in output
    assert all(path.exists() for path in witnesses)


def test_named_home_does_not_erase_siblings_or_desktop_data(layout, monkeypatch):
    home, witnesses, _ = layout
    active = home / "profiles" / "active"
    active.mkdir()
    config = active / "config.yaml"
    config.write_text("model: selected", encoding="utf-8")
    userdata = home.parent / "desktop-data"
    userdata.mkdir()
    (userdata / "preferences.json").write_text("keep", encoding="utf-8")
    monkeypatch.setenv("HERMES_HOME", str(active))
    monkeypatch.setattr(uninstall, "get_hermes_home", lambda: active)
    uninstall.run_data_uninstall(SimpleNamespace(yes=True))
    assert not config.exists()
    assert all(path.exists() for path in witnesses)
    assert (userdata / "preferences.json").read_text(encoding="utf-8") == "keep"


def test_directory_replaced_with_a_link_does_not_expand_removal(layout, tmp_path):
    from hermes_cli.data_cleanup import plan_data_removal, remove_data

    home, _, _ = layout
    original = home / "workspace"
    foreign = tmp_path / "foreign"
    foreign.mkdir()
    witness = foreign / "notes.txt"
    witness.write_text("not Hermes data", encoding="utf-8")
    probe = tmp_path / "symlink-probe"
    try:
        probe.symlink_to(foreign, target_is_directory=True)
    except OSError as exc:
        pytest.skip(f"native symlink creation unavailable: {exc}")
    probe.unlink()
    plan = plan_data_removal(home, uninstall.get_project_root())
    original.rename(home / "workspace-moved")
    original.symlink_to(foreign, target_is_directory=True)
    _, failures = remove_data(plan)
    assert failures
    assert witness.read_text(encoding="utf-8") == "not Hermes data"


def test_data_only_preserves_the_containing_bundled_application(layout, monkeypatch):
    import json
    from hermes_cli.bundled_app import PAYLOAD_DIR_NAME

    home, _, data = layout
    app = home / "installed-app"
    payload = app / "resources" / PAYLOAD_DIR_NAME
    project = payload / "repo"
    project.mkdir(parents=True)
    (project / "install-stamp.json").write_text(json.dumps({"payload": "bundled"}), encoding="utf-8")
    shell = app / "Hermes.exe"
    shell.write_bytes(b"retained app bytes")
    (payload / "venv").mkdir()
    manifest = payload / "manifest.json"
    manifest.write_text(json.dumps({"repo": "repo", "venv": "venv"}), encoding="utf-8")
    monkeypatch.setattr(uninstall, "get_project_root", lambda: project)
    uninstall.run_data_uninstall(SimpleNamespace(yes=True))
    assert shell.read_bytes() == b"retained app bytes"
    assert manifest.is_file()
    assert all(not path.exists() for path in data)


def test_data_only_works_from_a_self_contained_runtime_without_an_app(layout, monkeypatch):
    """A Termux-shaped runtime (sealed, APT-owned, no Electron app around it)
    must plan a data-only removal instead of hunting for a desktop app."""
    import json

    home, _, data = layout
    package = home.parent / "usr" / "lib" / "hermes-agent"
    project = package / "app"
    (project / "hermes_cli").mkdir(parents=True)
    (project / "hermes_cli" / "__init__.py").write_text("", encoding="utf-8")
    (project / "install-stamp.json").write_text(json.dumps(
        {"payload": "runtime", "distribution": "apt-termux", "updateMechanism": "external"}), encoding="utf-8")
    (package / "venv").mkdir()
    monkeypatch.setattr(uninstall, "get_project_root", lambda: project)
    uninstall.run_data_uninstall(SimpleNamespace(yes=True))
    assert all(not path.exists() for path in data)
    assert (project / "install-stamp.json").is_file() and (package / "venv").is_dir()
