from __future__ import annotations

import errno
import json
from pathlib import Path

import pytest

from retention_control import EXPECTED, RetentionError, verify
from strict_rerun_controller import retention_gated

HERE = Path(__file__).parent
PROOF = HERE / "retention-store/objects" / str(EXPECTED["archive_root_sha256"]) / "retention-proof.json"


def test_retention_metadata_binds_candidate_lifecycle_and_every_object_hash() -> None:
    result = verify(PROOF)
    metadata = json.loads((PROOF.parent / "retention-metadata.json").read_bytes())
    assert result["status"] == "PASS"
    assert metadata["candidate_digest"] == EXPECTED["candidate_digest"]
    assert metadata["lifecycle_root_sha256"] == EXPECTED["lifecycle_root_sha256"]
    assert metadata["lifecycle_seal_sha256"] == EXPECTED["lifecycle_seal_sha256"]
    assert metadata["run_id"] == EXPECTED["run_id"]
    assert metadata["retain_until_utc"] == "2033-08-17T00:00:00Z"
    assert len(metadata["archive_objects"]) == EXPECTED["archive_entry_count"]


def test_modification_deletion_denied_but_verification_reads_succeed() -> None:
    target = PROOF.parent / "archive/manifest.json"
    original = target.read_bytes()
    with pytest.raises(OSError) as modify:
        target.write_bytes(b"tamper")
    assert modify.value.errno in {errno.EPERM, errno.EACCES}
    with pytest.raises(OSError) as delete:
        target.unlink()
    assert delete.value.errno in {errno.EPERM, errno.EACCES}
    assert target.read_bytes() == original
    assert verify(PROOF)["status"] == "PASS"


def test_cleanup_controller_refuses_before_action_without_retention_proof(tmp_path: Path) -> None:
    marker = tmp_path / "cleanup-ran"
    with pytest.raises(RetentionError, match="retention proof is required"):
        retention_gated(None, lambda: marker.write_text("ran"))
    assert not marker.exists()


def test_cleanup_controller_refuses_tampered_or_unsealed_proof_before_action(tmp_path: Path) -> None:
    marker = tmp_path / "cleanup-ran"
    fake = tmp_path / "retention-proof.json"
    fake.write_text("{}")
    with pytest.raises(RetentionError):
        retention_gated(fake, lambda: marker.write_text("ran"))
    assert not marker.exists()


def test_cleanup_controller_proceeds_only_after_real_prevention_proof(tmp_path: Path) -> None:
    marker = tmp_path / "cleanup-ran"
    value = retention_gated(PROOF, lambda: marker.write_text("authorized"))
    assert value == len("authorized")
    assert marker.read_text() == "authorized"
