#!/usr/bin/env python3
"""Validate content YAML files against their JSON schemas.

Schema mapping is by directory context:
  campaign.yaml       → campaign.schema.json
  system.yaml         → system.schema.json
  station.yaml        → station.schema.json
  district.yaml       → district.schema.json
  npcs/*.yaml         → npc-profile.schema.json
  locations/*.yaml    → location.schema.json
  triangles/*.yaml    → triangle.schema.json
  dialogue/**/*.yaml  → dialogue-pool.schema.json
  monologue/**/*.yaml → monologue-pool.schema.json
  routines/*.yaml     → routine.schema.json

Files under global/ and content.yaml are skipped (no schema yet).

Exit code 0 = all valid, 1 = validation errors found.
"""

import json
import sys
from pathlib import Path

import jsonschema
import yaml

CONTENT_DIR = Path(__file__).resolve().parent.parent / "content"
SCHEMA_DIR = CONTENT_DIR / "_schema"

# Map directory parent name (or filename) to schema file
FILENAME_SCHEMAS = {
    "campaign.yaml": "campaign.schema.json",
    "system.yaml": "system.schema.json",
    "station.yaml": "station.schema.json",
    "district.yaml": "district.schema.json",
}

DIR_SCHEMAS = {
    "npcs": "npc-profile.schema.json",
    "locations": "location.schema.json",
    "triangles": "triangle.schema.json",
    "dialogue": "dialogue-pool.schema.json",
    "monologue": "monologue-pool.schema.json",
    "routines": "routine.schema.json",
}


def resolve_schema(yaml_path: Path) -> Path | None:
    """Determine which schema applies to a content YAML file."""
    name = yaml_path.name
    if name in FILENAME_SCHEMAS:
        return SCHEMA_DIR / FILENAME_SCHEMAS[name]

    # Walk up parents to find a matching directory name
    rel = yaml_path.relative_to(CONTENT_DIR)
    for part in reversed(rel.parts[:-1]):
        if part in DIR_SCHEMAS:
            return SCHEMA_DIR / DIR_SCHEMAS[part]

    return None


def main() -> int:
    errors = 0
    validated = 0
    skipped = 0

    # Cache loaded schemas
    schema_cache: dict[str, dict] = {}

    campaigns_dir = CONTENT_DIR / "campaigns"
    if not campaigns_dir.exists():
        print(f"No campaigns directory at {campaigns_dir}", file=sys.stderr)
        return 1

    yaml_files = sorted(campaigns_dir.rglob("*.yaml"))
    if not yaml_files:
        print("No YAML files found under campaigns/", file=sys.stderr)
        return 1

    for yaml_path in yaml_files:
        schema_path = resolve_schema(yaml_path)
        if schema_path is None:
            skipped += 1
            continue

        if not schema_path.exists():
            print(f"MISSING SCHEMA: {schema_path.name} for {yaml_path.relative_to(CONTENT_DIR)}")
            errors += 1
            continue

        # Load schema (cached)
        schema_key = str(schema_path)
        if schema_key not in schema_cache:
            with open(schema_path) as f:
                schema_cache[schema_key] = json.load(f)
        schema = schema_cache[schema_key]

        # Load YAML
        try:
            with open(yaml_path) as f:
                data = yaml.safe_load(f)
        except yaml.YAMLError as e:
            print(f"YAML ERROR: {yaml_path.relative_to(CONTENT_DIR)}: {e}")
            errors += 1
            continue

        if data is None:
            # Comment-only or empty placeholder files are valid stubs
            skipped += 1
            continue

        # Validate
        try:
            jsonschema.validate(instance=data, schema=schema)
            validated += 1
        except jsonschema.ValidationError as e:
            rel = yaml_path.relative_to(CONTENT_DIR)
            print(f"INVALID: {rel}")
            print(f"  Schema: {schema_path.name}")
            print(f"  Error:  {e.message}")
            if e.absolute_path:
                print(f"  Path:   {'.'.join(str(p) for p in e.absolute_path)}")
            errors += 1

    print(f"\nValidated {validated} files, {skipped} skipped, {errors} errors")
    return 1 if errors else 0


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