#!/usr/bin/env python3
"""Fail packaging when CARBON schema IDs drift from the OpenTest.ai-based registry."""

from __future__ import annotations

import json
import re
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
REGISTRY_PATH = ROOT / "runtime" / "carbon" / "references" / "schemas.json"
SCHEMA_PATTERN = re.compile(r"carbon\.[a-z0-9.-]+/v\d+")
SOURCE_ROOTS = [ROOT / "runtime", ROOT / "server", ROOT / "ui", ROOT / "skills"]
TEXT_SUFFIXES = {".cjs", ".html", ".js", ".json", ".md", ".mjs", ".py", ".sh", ".ts", ".yaml", ".yml"}
CLASSES = (
    "testcaseBasedSchemas",
    "bugBasedSchemas",
    "testcaseAndBugBasedSchemas",
    "operationalEnvelopeSchemas",
    "legacySchemas",
)


def source_schema_ids() -> set[str]:
    found: set[str] = set()
    for source_root in SOURCE_ROOTS:
        for path in source_root.rglob("*"):
            if not path.is_file() or path.suffix.lower() not in TEXT_SUFFIXES or path == REGISTRY_PATH:
                continue
            found.update(SCHEMA_PATTERN.findall(path.read_text(encoding="utf-8", errors="ignore")))
    return found


registry = json.loads(REGISTRY_PATH.read_text(encoding="utf-8"))
assert registry["schema"] == "carbon.schema-registry/v1"
assert registry["openTestAi"]["name"] == "OpenTest.ai"
assert registry["openTestAi"]["url"] == "https://www.opentest.ai/"
assert registry["openTestAi"]["license"] == "MIT"

testcase = registry["openTestAi"]["formats"]["testcase"]
bug = registry["openTestAi"]["formats"]["bug"]
assert (testcase["schema"], testcase["version"], testcase["required"]) == ("otai/testcase", "v1", ["title"])
assert (bug["schema"], bug["version"], bug["required"]) == ("otai/bug", "v1", ["bug_title"])
assert testcase["fields"] == ["title", "goal", "steps"]
assert testcase["stepFields"] == ["description", "thinking", "action", "target", "value", "expected"]
assert "prompt_to_fix_this_issue" in bug["fields"]

policy = registry["policy"]
assert policy["newSchemaRegistrationRequired"] is True
memberships: dict[str, list[str]] = {}
for class_name in CLASSES:
    values = policy[class_name]
    assert isinstance(values, list) and values, f"{class_name} must be a non-empty list"
    for schema_id in values:
        memberships.setdefault(schema_id, []).append(class_name)

duplicates = {key: value for key, value in memberships.items() if len(value) != 1}
assert not duplicates, f"Schema IDs must belong to exactly one governance class: {duplicates}"

source_ids = source_schema_ids()
registered_ids = set(memberships)
missing = sorted(source_ids - registered_ids)
legacy_ids = set(policy["legacySchemas"])
stale = sorted(registered_ids - source_ids - legacy_ids)
assert not missing, f"Register and classify new CARBON schema IDs in schemas.json: {missing}"
assert not stale, f"Remove or restore stale CARBON schema registrations: {stale}"

portable = set(policy["testcaseBasedSchemas"] + policy["bugBasedSchemas"] + policy["testcaseAndBugBasedSchemas"])
assert portable, "At least one portable OpenTest.ai-based CARBON schema is required"
assert not portable.intersection(policy["operationalEnvelopeSchemas"]), "Operational envelopes cannot claim OpenTest.ai conformance"

sys.path.insert(0, str(ROOT / "runtime" / "carbon" / "scripts"))
from carbon_run import normalize_test  # noqa: E402

minimal = normalize_test({"title": "Boundary value survives", "goal": "Validate the boundary"}, set())
assert minimal["title"] == "Boundary value survives"
assert minimal["priority"] == "P2"
assert minimal["id"].startswith("OTAI-")
assert minimal["schemaOrigin"]["format"] == "otai/testcase"

structured = normalize_test({
    "title": "Structured OpenTest.ai step",
    "steps": [{"description": "Enter the maximum value", "action": "fill", "target": "#amount", "value": "999", "expected": "Accepted"}],
}, set())
assert structured["steps"] == ["Enter the maximum value"]
assert structured["openTestSteps"][0]["expected"] == "Accepted"

print(f"PASS: {len(source_ids)} CARBON schema IDs are registered once; portable test and bug schemas cite OpenTest.ai v1 origins.")
