#!/usr/bin/env python3
"""Validate canonical resume data, generation sources, and generated documents.

Usage:
  python resume_builder/helpers/validate_resume_system.py
  python resume_builder/helpers/validate_resume_system.py --document output/Acme/resume.tex
"""

from __future__ import annotations

import argparse
import json
import re
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[2]
CLAIMS_PATH = ROOT / "resume_builder" / "canonical" / "claims.json"
HISTORY_PATH = ROOT / "resume_builder" / "canonical" / "historical_outputs.json"


def load_json(path: Path) -> dict:
    with path.open(encoding="utf-8") as handle:
        return json.load(handle)


def read_text(path: Path) -> str:
    return path.read_text(encoding="utf-8")


def canonical_checks(claims: dict, history: dict) -> tuple[list[str], list[str]]:
    errors: list[str] = []
    warnings: list[str] = []

    if claims.get("schema_version") != 1:
        errors.append("claims.json schema_version must be 1")
    if history.get("schema_version") != 1:
        errors.append("historical_outputs.json schema_version must be 1")

    for key in ("identity", "education", "employment", "claims", "skills"):
        if not claims.get(key):
            errors.append(f"claims.json missing non-empty {key}")

    for collection in ("education", "employment", "claims"):
        ids = [item.get("id") for item in claims.get(collection, [])]
        if None in ids:
            errors.append(f"{collection} contains an item without id")
        duplicates = sorted({item for item in ids if ids.count(item) > 1})
        if duplicates:
            errors.append(f"duplicate {collection} ids: {', '.join(duplicates)}")

    skills = claims.get("skills", [])
    skill_names = [item.get("name") for item in skills]
    duplicates = sorted({item for item in skill_names if skill_names.count(item) > 1})
    if duplicates:
        errors.append(f"duplicate skills: {', '.join(duplicates)}")
    for skill in skills:
        if skill.get("output") not in {
            "allowed",
            "allowed-with-context",
            "certification-context-only",
            "forbidden",
        }:
            errors.append(f"invalid output policy for skill {skill.get('name')}")

    config = read_text(ROOT / "config.md")
    bundle_names = re.findall(r"\|\s*(bundle_[a-z0-9_]+\.md)\s*\|", config)
    for bundle_name in bundle_names:
        if not (ROOT / "resume_builder" / "bundles" / bundle_name).exists():
            errors.append(f"configured bundle does not exist: {bundle_name}")

    expected_files = [
        ROOT / "resume_builder" / "templates" / "resume_template.tex",
        ROOT / "resume_builder" / "reference" / "resume_reference.md",
        ROOT / "resume_builder" / "reference" / "critique_framework.md",
    ]
    for path in expected_files:
        if not path.exists():
            errors.append(f"required workflow file missing: {path.relative_to(ROOT)}")

    history_folders: list[str] = []
    for key in ("unsafe_do_not_reuse", "historical_revalidate"):
        for item in history.get(key, []):
            history_folders.append(item["folder"] if isinstance(item, dict) else item)
    duplicates = sorted({item for item in history_folders if history_folders.count(item) > 1})
    if duplicates:
        errors.append(f"historical output folders classified twice: {', '.join(duplicates)}")

    if claims["identity"].get("swiss_permit", "").startswith("UNVERIFIED"):
        warnings.append("Swiss permit type remains unverified; generators must ask before naming it")
    return errors, warnings


def workflow_checks() -> list[str]:
    errors: list[str] = []
    checks = {
        ROOT / "resume_builder" / "templates" / "resume_template.tex": [
            "Research Experience",
            "FLIPPED format",
            "Selected Publications",
        ],
        ROOT / "resume_builder" / "reference" / "resume_reference.md": [
            "ALL variable bullets",
            "<= 3 lines white space",
            "20-21 variable bullets",
        ],
        ROOT / ".agents" / "skills" / "critique" / "SKILL.md": [
            "Publications 10%",
            "Eight-Dimension Scoring",
        ],
    }
    for path, forbidden_phrases in checks.items():
        text = read_text(path).lower()
        for phrase in forbidden_phrases:
            if phrase.lower() in text:
                errors.append(f"obsolete workflow rule remains in {path.relative_to(ROOT)}: {phrase}")
    return errors


def scan_document(path: Path, claims: dict) -> list[str]:
    errors: list[str] = []
    text = read_text(path)
    lowered = text.lower()
    for pattern in claims.get("global_forbidden_output_patterns", []):
        if pattern.lower() in lowered:
            errors.append(f"{path}: forbidden output pattern: {pattern}")
    for skill in claims.get("skills", []):
        if skill.get("output") == "forbidden" and skill["name"].lower() in lowered:
            errors.append(f"{path}: forbidden or unverified skill: {skill['name']}")
    if "\\begin{rsubsection}" in lowered:
        for line_number, line in enumerate(text.splitlines(), 1):
            if "\\begin{rSubsection}" not in line:
                continue
            if re.search(r"Production Ownership|AI-Ready|Customer-Embedded|Shipping ML", line, re.I):
                errors.append(f"{path}:{line_number}: marketing theme used before formal employer/title")
    return errors


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--document", action="append", default=[], help="Generated .tex file to validate")
    args = parser.parse_args()

    claims = load_json(CLAIMS_PATH)
    history = load_json(HISTORY_PATH)
    errors, warnings = canonical_checks(claims, history)
    errors.extend(workflow_checks())
    for document in args.document:
        path = Path(document)
        if not path.is_absolute():
            path = ROOT / path
        if not path.exists():
            errors.append(f"document not found: {path}")
        else:
            errors.extend(scan_document(path, claims))

    for warning in warnings:
        print(f"WARN: {warning}")
    for error in errors:
        print(f"ERROR: {error}")
    if errors:
        print(f"FAIL: {len(errors)} error(s), {len(warnings)} warning(s)")
        return 1
    print(f"PASS: canonical system valid ({len(warnings)} warning(s))")
    return 0


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