#!/usr/bin/env python3
"""Self-check the complete courseware-visuals-qa skill package."""

from __future__ import annotations

import argparse
import json
import py_compile
import re
import shutil
import subprocess
import sys
from pathlib import Path


REQUIRED_FILES = [
    "SKILL.md",
    "references/specification.md",
    "references/visual-playbook.md",
    "references/qa-playbook.md",
    "references/examples.md",
    "references/troubleshooting.md",
    "assets/semantic-visual-starter.js",
    "assets/design-tokens.json",
    "assets/visual-manifest.schema.json",
    "assets/visual-manifest.example.json",
    "assets/audit-report-template.md",
    "scripts/audit_courseware_visuals.py",
    "scripts/validate_visual_manifest.py",
    "scripts/check_skill_package.py",
    "evals/evals.json",
    "evals/trigger-evals.json",
]
KEBAB = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")


def frontmatter(text: str) -> dict[str, str]:
    if not text.startswith("---\n"):
        return {}
    end = text.find("\n---\n", 4)
    if end < 0:
        return {}
    result: dict[str, str] = {}
    for line in text[4:end].splitlines():
        if line.startswith(" ") or ":" not in line:
            continue
        key, value = line.split(":", 1)
        result[key.strip()] = value.strip()
    return result


def markdown_links(text: str) -> list[str]:
    return re.findall(r"\[[^\]]+\]\(([^)]+)\)", text)


def main() -> int:
    parser = argparse.ArgumentParser(description="Check required files and syntax for this skill")
    parser.add_argument("skill_dir", nargs="?", default=".")
    args = parser.parse_args()
    root = Path(args.skill_dir).resolve()
    errors: list[str] = []
    warnings: list[str] = []

    for relative in REQUIRED_FILES:
        if not (root / relative).is_file():
            errors.append(f"Missing required file: {relative}")

    skill_path = root / "SKILL.md"
    if skill_path.is_file():
        text = skill_path.read_text(encoding="utf-8")
        meta = frontmatter(text)
        name = meta.get("name", "")
        description = meta.get("description", "")
        if not name or not KEBAB.fullmatch(name) or len(name) > 64:
            errors.append("frontmatter name must be kebab-case and no longer than 64 characters")
        if not description or len(description) > 1024:
            errors.append("frontmatter description must contain 1-1024 characters")
        if len(text.splitlines()) > 500:
            errors.append("SKILL.md must stay under 500 lines")
        for link in markdown_links(text):
            if "://" in link or link.startswith("#"):
                continue
            if not (root / link).exists():
                errors.append(f"Broken SKILL.md reference: {link}")

    for relative in [
        "assets/design-tokens.json",
        "assets/visual-manifest.schema.json",
        "assets/visual-manifest.example.json",
        "evals/evals.json",
        "evals/trigger-evals.json",
    ]:
        path = root / relative
        if path.is_file():
            try:
                json.loads(path.read_text(encoding="utf-8"))
            except json.JSONDecodeError as exc:
                errors.append(f"Invalid JSON {relative}: line {exc.lineno}, column {exc.colno}: {exc.msg}")

    for path in (root / "scripts").glob("*.py") if (root / "scripts").is_dir() else []:
        try:
            py_compile.compile(str(path), doraise=True)
        except py_compile.PyCompileError as exc:
            errors.append(f"Python syntax error in {path.name}: {exc.msg}")

    validator = root / "scripts/validate_visual_manifest.py"
    example = root / "assets/visual-manifest.example.json"
    if validator.is_file() and example.is_file():
        result = subprocess.run([sys.executable, str(validator), str(example)], capture_output=True, text=True)
        if result.returncode:
            errors.append("Example manifest failed validation: " + (result.stdout + result.stderr).strip())

    node = shutil.which("node")
    starter = root / "assets/semantic-visual-starter.js"
    if node and starter.is_file():
        result = subprocess.run([node, "--check", str(starter)], capture_output=True, text=True)
        if result.returncode:
            errors.append("JavaScript syntax error: " + (result.stdout + result.stderr).strip())
    elif starter.is_file():
        warnings.append("Node.js not found; skipped JavaScript syntax check")

    print(f"Skill package: {root}")
    print(f"Required files: {len(REQUIRED_FILES) - sum(1 for f in REQUIRED_FILES if not (root / f).is_file())}/{len(REQUIRED_FILES)}")
    for warning in warnings:
        print(f"WARNING: {warning}")
    if errors:
        print(f"FAILED: {len(errors)} error(s)")
        for error in errors:
            print(f"- {error}")
        return 1
    print("PASS: structure, references, JSON, Python, manifest example, and JavaScript are valid")
    return 0


if __name__ == "__main__":
    sys.exit(main())

