import json
import tempfile
import unittest
from pathlib import Path

from gnos.core.attest import AttestationError, attest_manifest_bytes_shallow
from gnos.core.hash import sha256_hex
from gnos.core.store import ObjectStore
from gnos.manifest.codec import canonical_json_bytes
from gnos.cli.main import main


class TestAttestManifestShallow(unittest.TestCase):
    def test_attest_manifest_shallow_ok(self) -> None:
        obj = {
            "type": "derived-manifest",
            "version": 1,
            "doc_id": "0" * 64,
            "kind": "example",
            "payload": {"x": 1},
        }
        manifest_bytes = json.dumps(obj, separators=(",", ":"), sort_keys=False).encode("utf-8")
        expected_hash = sha256_hex(canonical_json_bytes(obj))
        actual_hash = attest_manifest_bytes_shallow(manifest_bytes, expected_manifest_hash=expected_hash)
        self.assertEqual(actual_hash, expected_hash)

    def test_attest_manifest_shallow_mismatch(self) -> None:
        obj = {"type": "derived-manifest", "version": 1, "doc_id": "0" * 64}
        manifest_bytes = json.dumps(obj, separators=(",", ":"), sort_keys=True).encode("utf-8")
        bad_hash = "1" * 64
        with self.assertRaises(AttestationError):
            attest_manifest_bytes_shallow(manifest_bytes, expected_manifest_hash=bad_hash)

    def test_cli_attest_manifest_shallow(self) -> None:
        obj = {
            "type": "derived-manifest",
            "version": 1,
            "doc_id": "0" * 64,
            "kind": "example",
            "payload": {"x": 1},
        }
        manifest_bytes = json.dumps(obj, separators=(",", ":"), sort_keys=False).encode("utf-8")
        manifest_hash = sha256_hex(canonical_json_bytes(obj))
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            old_cwd = Path.cwd()
            try:
                import os

                os.chdir(root)
                store = ObjectStore(root / ".gnos")
                store.init()
                store.put(manifest_hash, manifest_bytes)
                exit_code = main(["attest", "manifest", manifest_hash, "--shallow"])
                self.assertEqual(exit_code, 0)
            finally:
                os.chdir(old_cwd)
