#!/usr/bin/env python3
"""Shared CARBON schema registry and bounded local migrations."""

from __future__ import annotations

import datetime as dt
import json
import os
import tempfile
from pathlib import Path
from typing import Any


REGISTRY_PATH = Path(__file__).resolve().parents[1] / "references" / "schemas.json"


def _load_registry() -> dict[str, Any]:
    try:
        value = json.loads(REGISTRY_PATH.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as error:
        raise RuntimeError(f"CARBON schema registry is unavailable: {error}") from error
    if value.get("schema") != "carbon.schema-registry/v1":
        raise RuntimeError("CARBON schema registry has an unsupported schema")
    if not isinstance(value.get("schemas"), dict) or not isinstance(value.get("legacy"), dict):
        raise RuntimeError("CARBON schema registry is incomplete")
    open_test = value.get("openTestAi")
    formats = open_test.get("formats") if isinstance(open_test, dict) else None
    policy = value.get("policy")
    if (
        open_test.get("url") != "https://www.opentest.ai/"
        or not isinstance(formats, dict)
        or formats.get("testcase", {}).get("required") != ["title"]
        or formats.get("bug", {}).get("required") != ["bug_title"]
        or not isinstance(policy, dict)
        or policy.get("newSchemaRegistrationRequired") is not True
    ):
        raise RuntimeError("CARBON schema registry is missing its OpenTest.ai origin or governance policy")
    return value


REGISTRY = _load_registry()
OPENTEST_AI = REGISTRY["openTestAi"]
INTENT_LIBRARY_SCHEMA = str(REGISTRY["schemas"]["intentLibrary"])
INTENT_TEST_SCHEMA = str(REGISTRY["schemas"]["intentTest"])
LEGACY_INTENT_LIBRARY_SCHEMAS = frozenset(map(str, REGISTRY["legacy"].get("intentLibrary", [])))


def schema_origin(kind: str, *, relationship: str = "CARBON extension") -> dict[str, str]:
    """Return portable schema provenance for test-case and bug artifacts."""
    if kind not in {"testcase", "bug"}:
        raise ValueError("OpenTest.ai schema kind must be testcase or bug")
    format_value = OPENTEST_AI["formats"][kind]
    return {
        "name": str(OPENTEST_AI["name"]),
        "url": str(OPENTEST_AI["url"]),
        "format": str(format_value["schema"]),
        "version": str(format_value["version"]),
        "relationship": relationship,
    }


def _now() -> str:
    return dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")


def _atomic_json(path: Path, value: Any) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=path.parent, delete=False) as handle:
        json.dump(value, handle, indent=2, ensure_ascii=False)
        handle.write("\n")
        temporary = Path(handle.name)
    os.replace(temporary, path)


def ensure_intent_library(path: Path, project_root: Path, *, create: bool = True) -> dict[str, Any]:
    """Load the current library or migrate the one known legacy schema with a backup."""
    if not path.exists():
        if not create:
            raise ValueError(f"Cannot read CARBON intent-test library {path}: file does not exist")
        value = {
            "schema": INTENT_LIBRARY_SCHEMA,
            "schemaOrigin": schema_origin("testcase", relationship="container of CARBON testcase extensions"),
            "projectRoot": str(project_root),
            "tests": [],
            "updatedAt": _now(),
        }
        _atomic_json(path, value)
        return value
    if path.is_symlink() or not path.is_file():
        raise ValueError(f"CARBON intent-test library must be a regular file: {path}")
    try:
        value = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as error:
        raise ValueError(f"Cannot read CARBON intent-test library {path}: {error}") from error
    if not isinstance(value, dict) or not isinstance(value.get("tests"), list):
        raise ValueError(f"Unsupported intent-test library schema in {path}")
    schema = str(value.get("schema") or "")
    if schema == INTENT_LIBRARY_SCHEMA:
        if value.get("schemaOrigin") != schema_origin("testcase", relationship="container of CARBON testcase extensions"):
            value["schemaOrigin"] = schema_origin("testcase", relationship="container of CARBON testcase extensions")
            value["updatedAt"] = _now()
            _atomic_json(path, value)
        return value
    if schema not in LEGACY_INTENT_LIBRARY_SCHEMAS:
        raise ValueError(f"Unsupported intent-test library schema in {path}")
    backup = path.with_name(f"{path.stem}.pre-migration-{schema.replace('/', '-')}.json")
    if not backup.exists():
        _atomic_json(backup, value)
    migrated = {
        **value,
        "schema": INTENT_LIBRARY_SCHEMA,
        "schemaOrigin": schema_origin("testcase", relationship="container of CARBON testcase extensions"),
        "projectRoot": str(value.get("projectRoot") or project_root),
        "updatedAt": _now(),
    }
    _atomic_json(path, migrated)
    return migrated
