"""Auditor exploit regressions for the sealed v1.5 successor controller."""

from __future__ import annotations

import inspect
import json
import os
from pathlib import Path

import pytest

from scripts.execute_nutricoach_v150_sealed_live import sandbox_command
from scripts.nutricoach_v150_sealed_controller import (
    APPROVAL_PHRASE,
    OLD_APPROVAL_PHRASE,
    OLD_R71_APPROVAL_PHRASE,
    V2_APPROVAL_PHRASE,
    ConcreteLiveHost,
    DisposableService,
    SealedControllerError,
    execute_authorized,
    execute_disposable,
)
from tests.nutricoach_v150_transaction_support import prepare_weekly_profile


def target_fixture(root: Path) -> tuple[Path, ...]:
    profile = root / "profile"
    registry = profile / "customers/registry.json"
    config = profile / "config.yaml"
    unit = root / "gateway.service"
    dropin = root / "authority.conf"
    current = profile / ".strict-runtime/current/venv"
    (current / "bin").mkdir(parents=True)
    prepare_weekly_profile(profile, registry, config)
    _ = unit.write_text(f"ExecStart={current}/bin/python\n")
    _ = dropin.write_text(f'Environment="DUALCOACH_PROFILE_PACKAGE={current}"\n')
    _ = (current / "bin/python").write_text("current\n")
    return registry, config, unit, dropin


def test_public_entrypoint_has_no_caller_controlled_paths() -> None:
    signature = inspect.signature(execute_authorized)

    assert tuple(signature.parameters) == ("approval",)


def test_live_sandbox_preserves_only_user_runtime_bus_location() -> None:
    command = sandbox_command("approval")
    marker = command.index("XDG_RUNTIME_DIR")

    assert command[marker - 1] == "--setenv"
    assert command[marker + 1] == f"/run/user/{os.getuid()}"
    assert "DBUS_SESSION_BUS_ADDRESS" not in command


def test_concrete_adapter_runs_exact_stage_sequence(tmp_path: Path) -> None:
    paths = target_fixture(tmp_path)
    service = DisposableService()
    host = ConcreteLiveHost.disposable(tmp_path, service)

    receipt = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert receipt.startswith("sha256:")
    assert host.stages == [
        "stop",
        "post_stop_snapshot",
        "stopped_probe",
        "install_exact_wheels",
        "off_smoke_channel_inbox_off",
        "capacity_dry_run",
        "weekly_and_capacity_apply",
        "weekly_startup_smoke",
        "switch_unit_dropin",
        "reload",
        "start",
        "post_fence",
    ]
    assert service.running
    assert (
        json.loads(paths[0].read_text())["admission_policy"]["max_enabled_customers"]
        == 5
    )


@pytest.mark.parametrize(
    "error",
    [
        RuntimeError("runtime"),
        ValueError("value"),
        AssertionError("assertion"),
        KeyboardInterrupt(),
        SystemExit(7),
        OSError("os"),
    ],
)
def test_every_base_exception_rolls_back_and_consumes_globally(
    tmp_path: Path,
    error: BaseException,
) -> None:
    paths = target_fixture(tmp_path)
    before = tuple(path.read_bytes() for path in paths)
    service = DisposableService()
    host = ConcreteLiveHost.disposable(tmp_path, service, fault=error)

    with pytest.raises(type(error)):
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert tuple(path.read_bytes() for path in paths) == before
    assert service.running
    assert host.ledger_consumed()
    with pytest.raises(SealedControllerError, match="already_used"):
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)


def test_logs_may_append_but_protected_drift_is_refused(tmp_path: Path) -> None:
    paths = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())
    logs = tmp_path / "profile/logs"
    logs.mkdir()
    _ = (logs / "agent.log").write_text("before\n")
    _ = (logs / "errors.log").write_text("before\n")
    host.capture_preflight()
    with (logs / "agent.log").open("a") as stream:
        _ = stream.write("append\n")
    host.verify_preflight()
    with paths[0].open("a") as stream:
        _ = stream.write("drift\n")

    with pytest.raises(RuntimeError, match="protected_drift"):
        host.verify_preflight()


def test_concrete_rollback_removes_all_created_paths(tmp_path: Path) -> None:
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(
        tmp_path,
        DisposableService(),
        fault=ValueError("post-switch"),
        fault_stage="post_fence",
    )

    with pytest.raises(ValueError, match="post-switch"):
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert not host.successor_root.exists()
    assert not host.weekly_authority.exists()
    assert not host.network_events
    assert not host.telegram_events
    assert not host.provider_events


@pytest.mark.parametrize(
    "stage",
    [
        "stop",
        "post_stop_snapshot",
        "stopped_probe",
        "install_exact_wheels",
        "off_smoke_channel_inbox_off",
        "capacity_dry_run",
        "weekly_and_capacity_apply",
        "weekly_startup_smoke",
        "switch_unit_dropin",
        "reload",
        "start",
        "post_fence",
    ],
)
def test_each_concrete_stage_fault_restores_exact_target(
    tmp_path: Path,
    stage: str,
) -> None:
    paths = target_fixture(tmp_path)
    before = tuple(path.read_bytes() for path in paths)
    service = DisposableService()
    host = ConcreteLiveHost.disposable(
        tmp_path,
        service,
        fault=ValueError(stage),
        fault_stage=stage,
    )

    with pytest.raises(ValueError, match=stage):
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert tuple(path.read_bytes() for path in paths) == before
    assert service.running
    assert host.ledger_consumed()
    assert not host.successor_root.exists()
    assert not host.weekly_authority.exists()


def test_old_approval_is_explicitly_non_reusable(tmp_path: Path) -> None:
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())

    with pytest.raises(SealedControllerError, match="superseded"):
        _ = execute_disposable(OLD_APPROVAL_PHRASE, tmp_path, host)

    assert not host.ledger_reserved()


def test_v2_approval_is_rejected_before_global_ledger(tmp_path: Path) -> None:
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())

    with pytest.raises(SealedControllerError, match="superseded"):
        _ = execute_disposable(V2_APPROVAL_PHRASE, tmp_path, host)

    assert not host.ledger_reserved()


def test_install_normalizes_only_successor_permissions(tmp_path: Path) -> None:
    _ = target_fixture(tmp_path)
    current = tmp_path / "profile/.strict-runtime/current"
    python = current / "venv/bin/python"
    python.chmod(0o444)
    for directory in sorted(
        (path for path in current.rglob("*") if path.is_dir()),
        reverse=True,
    ):
        directory.chmod(0o555)
    current.chmod(0o555)
    before_mode = python.stat().st_mode & 0o777
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())

    _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert python.stat().st_mode & 0o777 == before_mode
    assert host.successor_root.stat().st_mode & 0o200
    assert (host.successor_root / "venv/bin/python").stat().st_mode & 0o200


def test_permission_error_install_cleans_and_restarts_service(tmp_path: Path) -> None:
    _ = target_fixture(tmp_path)
    current = tmp_path / "profile/.strict-runtime/current"
    for path in (current, *current.rglob("*")):
        path.chmod(0o555 if path.is_dir() else 0o444)
    service = DisposableService()
    host = ConcreteLiveHost.disposable(
        tmp_path,
        service,
        fault=PermissionError("install denied"),
    )

    with pytest.raises(PermissionError, match="install denied"):
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert service.running
    assert not host.successor_root.exists()
    assert not host.weekly_authority.exists()


def test_secondary_cleanup_error_preserves_primary_and_restarts(
    tmp_path: Path,
) -> None:
    _ = target_fixture(tmp_path)
    service = DisposableService()
    primary = ValueError("primary install failure")
    host = ConcreteLiveHost.disposable(
        tmp_path,
        service,
        fault=primary,
        cleanup_fault=OSError("secondary cleanup failure"),
    )

    with pytest.raises(ValueError, match="primary install failure") as captured:
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    assert captured.value is primary
    assert service.running
    assert host.rollback_failures == ["created_remove:secondary cleanup failure"]
    assert not host.successor_root.exists()


def test_absent_channel_inbox_defaults_off_for_exact_live_config(
    tmp_path: Path,
) -> None:
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())
    live_config = Path("/home/cube/.hermes/profiles/dualcoachtest/config.yaml")
    _ = host.paths.config.write_bytes(live_config.read_bytes())

    host.off_smoke()

    assert host.stages == ["off_smoke_channel_inbox_off"]
    _ = host.paths.config.write_text("channel_inbox: true\n")
    with pytest.raises(RuntimeError, match="channel_inbox_on"):
        host.off_smoke()
