import copy
import subprocess
import tempfile
import unittest
from pathlib import Path

import yaml


ROOT = Path(__file__).resolve().parents[1]
VALIDATOR = ROOT / "tools" / "validate_registry.py"
REGISTRY = ROOT / "examples" / "solar-plant-example.yaml"


class RegistryValidationTests(unittest.TestCase):
    def setUp(self):
        self.registry = yaml.safe_load(REGISTRY.read_text())

    def validate(self, registry):
        with tempfile.NamedTemporaryFile("w", suffix=".yaml") as handle:
            yaml.safe_dump(registry, handle)
            handle.flush()
            return subprocess.run(
                ["python3", str(VALIDATOR), handle.name],
                capture_output=True,
                text=True,
                check=False,
            )

    def test_reference_registry_is_valid(self):
        result = self.validate(self.registry)
        self.assertEqual(result.returncode, 0, result.stdout + result.stderr)

    def test_cross_organization_portfolio_is_rejected(self):
        registry = copy.deepcopy(self.registry)
        registry["organizations"].append({"id": "other", "name": "Other", "status": "active"})
        registry["portfolios"].append(
            {"id": "other-sites", "organization_id": "other", "name": "Other Sites", "status": "active"}
        )
        registry["plants"][0]["portfolio_ids"].append("other-sites")
        result = self.validate(registry)
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("outside its organization", result.stdout)

    def test_unknown_topology_version_is_rejected(self):
        registry = copy.deepcopy(self.registry)
        registry["relationships"][0]["topology_version"] = 99
        result = self.validate(registry)
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("unknown topology version", result.stdout)

    def test_overlapping_active_topology_versions_are_rejected(self):
        registry = copy.deepcopy(self.registry)
        second = copy.deepcopy(registry["topologies"][0])
        second["version"] = 2
        second["valid_from"] = "2026-07-14T10:00:00Z"
        registry["topologies"].append(second)
        result = self.validate(registry)
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("active topology versions overlap", result.stdout)

    def test_duplicate_scoped_identity_is_rejected(self):
        registry = copy.deepcopy(self.registry)
        registry["measurement_points"].append(copy.deepcopy(registry["measurement_points"][0]))
        result = self.validate(registry)
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("duplicate measurement_point identity", result.stdout)

    def test_invalid_relationship_endpoint_kinds_are_rejected(self):
        registry = copy.deepcopy(self.registry)
        registry["relationships"][0]["type"] = "controls"
        result = self.validate(registry)
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("invalid endpoint kinds", result.stdout)

    def test_contains_cycle_is_rejected(self):
        registry = copy.deepcopy(self.registry)
        base = {
            "plant_id": "solar-example",
            "topology_id": "telemetry-infrastructure",
            "topology_version": 1,
            "type": "contains",
            "status": "active",
            "valid_from": "2026-07-13T10:00:00Z",
        }
        registry["relationships"].extend([
            {
                **base,
                "id": "rel-asset-device",
                "from": {"kind": "asset", "id": "plant-operations"},
                "to": {"kind": "device", "id": "edge-collector-01"},
            },
            {
                **base,
                "id": "rel-device-asset",
                "from": {"kind": "device", "id": "edge-collector-01"},
                "to": {"kind": "asset", "id": "plant-operations"},
            },
        ])
        result = self.validate(registry)
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("contains relationship cycle", result.stdout)

    def test_secret_key_is_rejected(self):
        registry = copy.deepcopy(self.registry)
        registry["devices"][0]["communication"] = {"password": "not-allowed"}
        result = self.validate(registry)
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("secret-like Registry key", result.stdout)


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