from __future__ import annotations

import copy
import sys
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))
import check_organizational_readiness as c
import strict_json_schema as s


class SixthGenerationAuditRegressions(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.manifest = s.load_json(
            ROOT / "manifests/organizational-readiness.template.json"
        )

    def reject(self, fn):
        with self.assertRaises(Exception):
            fn()

    def validate_schema(self, name, document):
        s.validate(document, s.load_json(ROOT / "schemas/evidence" / name))

    def test_sixth_commercial_two_letter_placeholder_like_parties(self):
        document = {"legalName": "NA"}
        party_schema = s.load_json(
            ROOT / "schemas/evidence/commercial-agreement.schema.json"
        )["properties"]["legalParties"]["items"]
        self.reject(lambda: s.validate(document, party_schema))

    def test_sixth_incident_arbitrary_exercise_digest_content(self):
        self.reject(
            lambda: self.validate_schema(
                "incident-exercise.schema.json", {"garbage": True}
            )
        )

    def test_sixth_contacts_wrong_channel_type_for_incident(self):
        self.assertNotIn(
            "email-alias", c.CONTACT_FUNCTION_CHANNEL_TYPES["incident"]
        )
        self.assertEqual(
            c.CONTACT_FUNCTION_CHANNEL_TYPES["incident"], {"paging-route"}
        )

    def test_sixth_contacts_unresolved_reachability_digests(self):
        schema = s.load_json(ROOT / "schemas/evidence/contact-control.schema.json")
        required = schema["properties"]["channels"]["items"]["required"]
        self.assertIn("reachabilityTestPath", required)
        self.assertIn("reachabilityTestSha256", required)

    def test_sixth_unlinkability_weak_self_declared_methodology(self):
        schema = s.load_json(
            ROOT / "schemas/evidence/unlinkability-test-results.schema.json"
        )
        method = schema["properties"]["methodology"]["properties"]
        self.assertEqual(method["methodologyId"]["const"], "vaultfire-chain-specific-unlinkability-v1")
        self.reject(lambda: s.validate(1, method["sampleCount"]))
        self.reject(lambda: s.validate(9499, method["confidenceLevelBps"]))

    def test_sixth_unlinkability_unresolved_log_digests(self):
        schema = s.load_json(
            ROOT / "schemas/evidence/unlinkability-test-results.schema.json"
        )
        required = schema["properties"]["tests"]["items"]["required"]
        self.assertIn("logPath", required)
        self.assertIn("logSha256", required)
        self.assertIn("combinedLogPath", schema["properties"]["summary"]["required"])

    def test_sixth_liability_incoherent_caps_and_placeholder_remedies(self):
        schema = s.load_json(ROOT / "schemas/evidence/bounded-liabilities.schema.json")
        self.reject(lambda: s.validate(["x"], schema["properties"]["remedies"]))
        self.reject(lambda: s.validate("x", schema["properties"]["residualLiability"]))
        caps = {
            "perEventCap": 999,
            "aggregateCap": 1,
            "maximumLoss": 999,
            "reserveAmount": 1,
            "maximumCoveredEvents": 1,
        }
        coherent = (
            caps["perEventCap"] <= caps["aggregateCap"]
            and caps["aggregateCap"]
            == caps["perEventCap"] * caps["maximumCoveredEvents"]
            and caps["maximumLoss"] == caps["aggregateCap"]
            and caps["reserveAmount"] >= caps["maximumLoss"]
        )
        self.assertFalse(coherent)


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