"""CC0-1.0. Receipt, negative-control and fresh native replay tests."""
import copy
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
import unittest
from observe import CASES, collect, scenario, sha
from build import validate

ROOT = Path(__file__).parent
IMG = os.environ.get("QEMU_IMG", "qemu-img")
IO = os.environ.get("QEMU_IO", "qemu-io")


class EvidenceTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.receipt = json.loads((ROOT / "results.json").read_text())

    def test_canonical_receipt(self):
        self.assertEqual(len(validate(self.receipt, ROOT / "observe.py")), 60)

    def test_duplicate_case_rejected(self):
        value = copy.deepcopy(self.receipt)
        value["rows"][-1] = copy.deepcopy(value["rows"][0])
        with self.assertRaisesRegex(RuntimeError, "Coverage"):
            validate(value, ROOT / "observe.py")

    def test_false_success_rejected(self):
        value = copy.deepcopy(self.receipt)
        value["rows"][1]["checkExit"] = 2
        with self.assertRaisesRegex(RuntimeError, "Outcome"):
            validate(value, ROOT / "observe.py")

    def test_wrong_hash_rejected(self):
        value = copy.deepcopy(self.receipt)
        value["rows"][0]["guestSha256"] = sha(b"wrong")
        with self.assertRaisesRegex(RuntimeError, "Guest hash"):
            validate(value, ROOT / "observe.py")

    def test_wrong_receipt_rejected(self):
        value = copy.deepcopy(self.receipt)
        value["rows"][0]["commands"][-1]["exitCode"] = 1
        with self.assertRaisesRegex(RuntimeError, "Receipt"):
            validate(value, ROOT / "observe.py")

    def test_harness_mismatch_rejected(self):
        value = copy.deepcopy(self.receipt)
        value["harnessSha256"] = "0" * 64
        with self.assertRaisesRegex(RuntimeError, "Harness"):
            validate(value, ROOT / "observe.py")

    def test_check_error_body_rejected(self):
        value = copy.deepcopy(self.receipt)
        report = json.loads(value["rows"][0]["commands"][-4]["stdout"])
        report["check-errors"] = 1
        value["rows"][0]["commands"][-4]["stdout"] = json.dumps(report)
        with self.assertRaisesRegex(RuntimeError, "Check report"):
            validate(value, ROOT / "observe.py")

    def test_boolean_exit_code_rejected(self):
        value = copy.deepcopy(self.receipt)
        value["rows"][0]["commands"][-1]["exitCode"] = False
        with self.assertRaisesRegex(RuntimeError, "Exit code type"):
            validate(value, ROOT / "observe.py")

    def test_missing_command_argument_rejected(self):
        value = copy.deepcopy(self.receipt)
        value["rows"][0]["commands"][-1]["command"] = ["qemu-img", "convert"]
        with self.assertRaisesRegex(RuntimeError, "Observer arguments"):
            validate(value, ROOT / "observe.py")

    def test_bad_case_rejected(self):
        with self.assertRaisesRegex(RuntimeError, "Invalid fixture"):
            scenario(IMG, IO, "not-a-case", False, 1)

    def test_bad_repetitions_rejected(self):
        with self.assertRaisesRegex(RuntimeError, "Repetitions"):
            collect(IMG, IO, 0)

    def test_existing_output_preserved(self):
        with tempfile.TemporaryDirectory() as tmp:
            target = Path(tmp) / "keep.json"
            target.write_bytes(b"keep")
            p = subprocess.run([sys.executable, "-B", str(ROOT / "observe.py"),
                                "--output", str(target)], capture_output=True, timeout=10)
            self.assertNotEqual(p.returncode, 0)
            self.assertEqual(target.read_bytes(), b"keep")

    def test_fresh_native_replay(self):
        img, io = shutil.which(IMG), shutil.which(IO)
        self.assertTrue(img and io, "Provide QEMU_IMG and QEMU_IO")
        result = collect(img, io, 1)
        self.assertEqual(len(validate(result, ROOT / "observe.py")), 2 * len(CASES))


if __name__ == "__main__":
    unittest.main()
