import importlib.util,json
from pathlib import Path
import pytest
HERE=Path(__file__).parent;S=importlib.util.spec_from_file_location("rc",HERE/"recovery_controller.py");assert S and S.loader
rc=importlib.util.module_from_spec(S);S.loader.exec_module(rc)
def sample():return {"version":3,"receipts":{"10":{"stage":"receipt","reason_code":"handled"}},"terminal_receipts":{"9":{"stage":"recovery_receipt","reason_code":"business_commit_reconciled","provenance_digest":"a"*64}},"terminal_failures":{str(rc.TARGET):{"stage":"blocked_receipt","reason_code":"handler_exception"}}}
def test_exact_target():rc.validate_target(sample())
@pytest.mark.parametrize("kind",["extra","conflict","reason","entry"])
def test_fail_closed(kind):
 v=sample()
 if kind=="extra":v["terminal_failures"]["1"]={"stage":"blocked_receipt","reason_code":"handler_exception"}
 elif kind=="conflict":v["receipts"][str(rc.TARGET)]={"stage":"receipt","reason_code":"handled"}
 elif kind=="reason":v["terminal_failures"][str(rc.TARGET)]["reason_code"]="other"
 else:v["receipts"]["10"]={"stage":"bad","reason_code":"handled"}
 with pytest.raises(rc.Closed):rc.validate_target(v)
def test_versions_and_unknown_keys():
 assert rc.parse_receipt(b'{"receipts":{},"version":1}')["version"]==1
 assert rc.parse_receipt(b'{"receipts":{},"terminal_receipts":{},"version":2}')["version"]==2
 with pytest.raises(rc.Closed):rc.parse_receipt(json.dumps({**sample(),"extra":1}).encode())
def test_create_append_only_private(tmp_path):
 p=tmp_path/"x";rc.create(p,b"x");assert p.read_bytes()==b"x" and stat_mode(p)==0o600
 with pytest.raises(FileExistsError):rc.create(p,b"y")
def stat_mode(p):return p.stat().st_mode&0o777
def test_inventory_excludes_locks(tmp_path,monkeypatch):
 p=tmp_path/"p";(p/"customers").mkdir(parents=True);(p/"customers/registry.json").write_text("{}");(p/"data/customers/c").mkdir(parents=True);(p/"data/customers/c/x.json").write_text("{}");(p/"data/customers/c/x.lock").write_text("");(p/"config.yaml").write_text("x: 1");monkeypatch.setattr(rc,"PROFILE",p);monkeypatch.setattr(rc,"CUSTOMER","c");monkeypatch.setattr(rc,"RECEIPT",p/"data/r.json");x=rc.inventory();assert "customers/registry.json" in x and "data/customers/c/x.json" in x and all(not k.endswith(".lock") for k in x)
