"""External runtime-authority safety regressions for the V15 successor."""

from __future__ import annotations

import os
from pathlib import Path
from unittest.mock import patch

import pytest

from gateway.platforms.task26_runtime_authority import (
    load_task26_production_authority,
)
from scripts.dualcoach_v111_disposable_fixture import write_runtime_authority
from scripts.nutricoach_v150_concrete_host import ConcreteLiveHost
from scripts.nutricoach_v150_sealed_controller import (
    APPROVAL_PHRASE,
    DisposableService,
    execute_disposable,
)
from tests.test_nutricoach_v150_sealed_controller import target_fixture


def test_committed_successor_is_current_in_external_runtime_authority(
    tmp_path: Path,
) -> None:
    # Given
    predecessor = "a" * 64
    external = tmp_path / "external-authority"
    pin, candidate = write_runtime_authority(external, predecessor)
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(tmp_path, DisposableService())
    _ = host.paths.dropin.write_text(
        "\n".join((
            f"LoadCredential=task26-authority-pin.json:{pin}",
            f"LoadCredential=task26-candidate-digest:{candidate}",
            "",
        )),
        encoding="utf-8",
    )

    # When
    _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    # Then
    credentials = host.paths.successor_runtime.parent / "runtime-authority"
    with patch.dict(
        os.environ,
        {"CREDENTIALS_DIRECTORY": str(credentials)},
        clear=False,
    ):
        source, successor = load_task26_production_authority(
            profile_root=host.paths.profile,
            package_root=tmp_path / "package",
        )
    assert successor == host.candidate_digest
    with source.authorize(successor, "activation") as snapshot:
        assert snapshot["candidate_digest"] == host.candidate_digest
    assert host.stages.index("promote_runtime_authority") < host.stages.index(
        "switch_unit_dropin"
    )


def test_external_authority_transition_restores_predecessor_after_failure(
    tmp_path: Path,
) -> None:
    # Given
    predecessor = "a" * 64
    external = tmp_path / "external-authority"
    pin, candidate = write_runtime_authority(external, predecessor)
    _ = target_fixture(tmp_path)
    host = ConcreteLiveHost.disposable(
        tmp_path,
        DisposableService(),
        fault=ValueError("post-promotion"),
        fault_stage="post_fence",
    )
    _ = host.paths.dropin.write_text(
        "\n".join((
            f"LoadCredential=task26-authority-pin.json:{pin}",
            f"LoadCredential=task26-candidate-digest:{candidate}",
            "",
        )),
        encoding="utf-8",
    )
    # When
    with pytest.raises(ValueError, match="post-promotion"):
        _ = execute_disposable(APPROVAL_PHRASE, tmp_path, host)

    # Then
    with patch.dict(
        os.environ,
        {
            "TASK26_AUTHORITY_PIN": str(pin),
            "TASK26_CANDIDATE_DIGEST_FILE": str(candidate),
        },
        clear=False,
    ):
        source, restored = load_task26_production_authority(
            profile_root=host.paths.profile,
            package_root=tmp_path / "package",
        )
    assert restored == predecessor
    with source.authorize(restored, "activation") as snapshot:
        assert snapshot["candidate_digest"] == predecessor
        assert snapshot["event_count"] == 4
    with pytest.raises(ValueError, match="not current or was revoked"):
        with source.authorize(host.candidate_digest, "activation"):
            pass
    assert not host.successor_root.exists()
