#!/usr/bin/env python3
import hashlib
import importlib.machinery
import importlib.util
import json
import os
import subprocess
import tarfile
import tempfile
import unittest
from pathlib import Path


SCRIPT_DIR = Path(__file__).resolve().parent
PLATFORM_ROOT = SCRIPT_DIR.parent.parent
ENGINE_ROOT = PLATFORM_ROOT.parent / "NODEDC_ENGINE_INFRA"
RUNNER_PATH = SCRIPT_DIR / "nodedc-deploy"
ENGINE_BUILDER = SCRIPT_DIR / "build-engine-mcp-ontology-sdk-artifact.mjs"
PLATFORM_BUILDER = SCRIPT_DIR / "build-platform-gelios-provider-v2-artifact.mjs"
ENGINE_ARTIFACT = (
    PLATFORM_ROOT
    / "infra/deploy-artifacts/nodedc-engine-mcp-control-plane-20260718-005.tgz"
)
PLATFORM_ARTIFACT = (
    PLATFORM_ROOT
    / "infra/deploy-artifacts/nodedc-platform-gelios-provider-v2-20260718-005.tgz"
)
ENGINE_SHA256 = "8d6e1581ebbba420984e2393b8c6f0f21e0b644f630c4ca6483a7cc4a0ae5c71"
PLATFORM_SHA256 = "e1b838ec265369af735766fc7d1bf23c5e05bd2d15ef65e2446b4f7efa7a1baa"


def load_runner():
    loader = importlib.machinery.SourceFileLoader("nodedc_engine_mcp_ontology_sdk", str(RUNNER_PATH))
    spec = importlib.util.spec_from_loader(loader.name, loader)
    module = importlib.util.module_from_spec(spec)
    loader.exec_module(module)
    return module


RUNNER = load_runner()


class EngineMcpOntologySdkTest(unittest.TestCase):
    def test_canonical_artifacts_have_pinned_digests_and_safe_members(self):
        for artifact, expected in (
            (ENGINE_ARTIFACT, ENGINE_SHA256),
            (PLATFORM_ARTIFACT, PLATFORM_SHA256),
        ):
            self.assertEqual(hashlib.sha256(artifact.read_bytes()).hexdigest(), expected)
            self.assertEqual(artifact.read_bytes()[4:8], b"\0\0\0\0")
            with tarfile.open(artifact, "r:gz") as archive:
                for member in archive:
                    self.assertTrue(member.isfile() or member.isdir())
                    self.assertFalse(Path(member.name).name.startswith("._"))

    def test_engine_builder_is_byte_reproducible(self):
        current_sha256 = {
            relative_path: hashlib.sha256((ENGINE_ROOT / relative_path).read_bytes()).hexdigest()
            for relative_path in RUNNER.ENGINE_MCP_ONTOLOGY_SDK_TARGET_SHA256
        }
        if current_sha256 != RUNNER.ENGINE_MCP_ONTOLOGY_SDK_TARGET_SHA256:
            self.skipTest("historical Ontology/SDK builder source has advanced to its exact successor")
        outputs = []
        with tempfile.TemporaryDirectory(prefix="nodedc-engine-mcp-ontology-sdk-") as directory:
            for index in range(2):
                target = Path(directory) / str(index)
                target.mkdir()
                env = os.environ.copy()
                env["NODEDC_DEPLOY_ARTIFACT_DIR"] = str(target)
                result = subprocess.run(
                    ["node", str(ENGINE_BUILDER), "20260718-005"],
                    cwd=PLATFORM_ROOT,
                    env=env,
                    check=True,
                    capture_output=True,
                    text=True,
                )
                outputs.append(Path(json.loads(result.stdout)["artifact"]).read_bytes())
        self.assertEqual(outputs[0], outputs[1])
        self.assertEqual(outputs[0], ENGINE_ARTIFACT.read_bytes())

    def test_platform_builder_is_byte_reproducible(self):
        outputs = []
        with tempfile.TemporaryDirectory(prefix="nodedc-platform-gelios-v2-") as directory:
            for index in range(2):
                target = Path(directory) / str(index)
                target.mkdir()
                env = os.environ.copy()
                env["NODEDC_DEPLOY_ARTIFACT_DIR"] = str(target)
                result = subprocess.run(
                    ["node", str(PLATFORM_BUILDER), "20260718-005"],
                    cwd=PLATFORM_ROOT,
                    env=env,
                    check=True,
                    capture_output=True,
                    text=True,
                )
                outputs.append(Path(json.loads(result.stdout)["artifact"]).read_bytes())
        self.assertEqual(outputs[0], outputs[1])
        self.assertEqual(outputs[0], PLATFORM_ARTIFACT.read_bytes())

    def test_engine_slice_is_exact_and_restarts_only_backend(self):
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            manifest, entries, payload = RUNNER.load_artifact(ENGINE_ARTIFACT, root)
            descriptor = RUNNER.validate_engine_mcp_ontology_sdk_payload(payload, entries)
        self.assertEqual(manifest["component"], "engine")
        self.assertEqual(tuple(entries), RUNNER.ENGINE_MCP_ONTOLOGY_SDK_ARTIFACT_ENTRIES)
        self.assertEqual(RUNNER.component_services("engine", entries), ("nodedc-backend",))
        self.assertEqual(RUNNER.component_builds("engine", entries), ())
        self.assertEqual(
            descriptor["source"]["gatewaySha256"],
            RUNNER.ENGINE_MCP_ONTOLOGY_SDK_TARGET_SHA256[
                RUNNER.ENGINE_NODE_INTELLIGENCE_GATEWAY_REL
            ],
        )

    def test_platform_provider_package_is_metadata_only(self):
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            manifest, entries, _payload = RUNNER.load_artifact(PLATFORM_ARTIFACT, root)
        self.assertEqual(manifest["component"], "platform")
        self.assertTrue(RUNNER.is_platform_provider_catalog_only(entries))
        self.assertEqual(RUNNER.component_services("platform", entries), ())
        self.assertEqual(RUNNER.component_builds("platform", entries), ())
        self.assertEqual(RUNNER.component_healthchecks("platform", entries, ()), ())

    def test_engine_payload_tampering_is_rejected(self):
        with tempfile.TemporaryDirectory() as directory:
            root = Path(directory)
            RUNNER.safe_extract(ENGINE_ARTIFACT, root)
            entries = RUNNER.parse_files_list(root / "files.txt")
            catalog = root / "payload/nodedc-source/server/assets/provider-packages/v1/catalog.json"
            catalog.write_text("{}\n", encoding="utf-8")
            with self.assertRaisesRegex(RUNNER.DeployError, "target sha256 mismatch"):
                RUNNER.validate_engine_mcp_ontology_sdk_payload(root / "payload", entries)


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