#!/usr/bin/env python3
"""Validate renderer API contract purity for key rendering components."""

from __future__ import annotations

import json
import re
from pathlib import Path
from typing import Any

INCLUDE_RE = re.compile(r"""^\s*#\s*include\s+(\"([^\"]+)\"|<([^>]+)>)""")

REPO_ROOT = Path(__file__).resolve().parents[2]

CHECKS = {
    "renderer_api": {
        "roots": [REPO_ROOT / "src" / "renderer_api"],
        "allowed_include_prefixes": ("foundation/", "renderer_api/"),
        "forbidden_include_tokens": (
            "renderer_gl/",
            "platform/",
            "platform_api/",
            "platform_",
            "opengl",
            "glad",
            "vulkan",
            "d3d",
            "directx",
            "metal",
            "appkit",
            "cocoa",
            "objc/",
            "windows.h",
            "x11/",
            "wayland-",
            "android/",
        ),
        "forbidden_body_tokens": (
            "OpenGl",
            "OpenGL",
            "opengl_",
            "GL_",
            "Vulkan",
            "Vk",
            "MTL",
            "D3D",
            "vulkan",
            "metal",
            "renderer_gl",
            "pp_platform_",
        ),
    },
    "paint_renderer": {
        "roots": [REPO_ROOT / "src" / "paint_renderer"],
        "allowed_include_prefixes": (
            "assets/",
            "document/",
            "foundation/",
            "paint/",
            "paint_renderer/",
            "renderer_api/",
        ),
        "forbidden_include_tokens": (
            "renderer_gl/",
            "platform/",
            "platform_api/",
            "platform_",
            "opengl",
            "glad",
            "vulkan",
            "d3d",
            "directx",
            "metal",
            "appkit",
            "cocoa",
            "objc/",
            "windows.h",
            "x11/",
            "wayland-",
            "android/",
        ),
        "forbidden_body_tokens": (
            "OpenGl",
            "OpenGL",
            "opengl_",
            "GL_",
            "Vulkan",
            "Vk",
            "MTL",
            "D3D",
            "vulkan",
            "metal",
            "renderer_gl",
            "pp_platform_",
        ),
    },
}

ALLOWED_EXTERNAL_PREFIXES = ("stb/",)


def is_forbidden_include(allowlist: tuple[str, ...], forbidden_tokens: tuple[str, ...], include: str) -> tuple[bool, str | None]:
    include_lower = include.lower()
    if any(token in include_lower for token in forbidden_tokens):
        token = next(token for token in forbidden_tokens if token in include_lower)
        return True, token

    if "/" in include and include_lower.startswith(ALLOWED_EXTERNAL_PREFIXES):
        return False, None

    if "/" in include and not any(include_lower.startswith(prefix) for prefix in allowlist):
        return True, "cross-component-include"
    return False, None


def scan_component(name: str, config: dict[str, Any]) -> list[dict[str, Any]]:
    violations: list[dict[str, Any]] = []
    for root in config["roots"]:
        for path in root.rglob("*"):
            if not path.is_file():
                continue
            if path.suffix.lower() not in {".cpp", ".cc", ".c", ".h", ".hpp", ".hh"}:
                continue

            text = path.read_text(encoding="utf-8").splitlines()
            for line_no, line in enumerate(text, start=1):
                include_match = INCLUDE_RE.match(line)
                if include_match:
                    include = (include_match.group(2) or include_match.group(3) or "").strip()
                    forbidden, reason = is_forbidden_include(
                        config["allowed_include_prefixes"],
                        config["forbidden_include_tokens"],
                        include,
                    )
                    if forbidden:
                        violations.append(
                            {
                                "component": name,
                                "file": str(path.relative_to(REPO_ROOT)),
                                "line": line_no,
                                "kind": "forbidden-include",
                                "include": include,
                                "detail": reason,
                                "text": line.strip(),
                            }
                        )

            joined = "\n".join(text)
            for token in config["forbidden_body_tokens"]:
                if token in joined:
                    violations.append(
                        {
                            "component": name,
                            "file": str(path.relative_to(REPO_ROOT)),
                            "line": 0,
                            "kind": "forbidden-body-token",
                            "include": token,
                            "detail": "backend- or platform-specific symbol in renderer contract path",
                            "text": "",
                        }
                    )

    return violations


def main() -> int:
    violations: list[dict[str, Any]] = []
    for component, config in CHECKS.items():
        violations.extend(scan_component(component, config))

    print(
        json.dumps(
            {
                "ok": len(violations) == 0,
                "summary": {
                    "componentCount": len(CHECKS),
                    "violationCount": len(violations),
                },
                "violations": violations,
            },
            separators=(",", ":"),
        )
    )
    return 0 if not violations else 1


if __name__ == "__main__":
    raise SystemExit(main())
