#!/usr/bin/env python3
"""
Validate Skill - Check a skill folder against standards.

Part of the genesis-architect skill.

Usage:
    python validate_skill.py <skill_path> [--strict]

Arguments:
    skill_path      Path to skill folder to validate
    --strict        Enable strict validation (all warnings = errors)

Examples:
    python validate_skill.py .claude/skills/piter-framework
    python validate_skill.py ./my-skill --strict

Output:
    Validation report with pass/fail status and issues found.
"""

import argparse
import json
import re
import sys
from pathlib import Path
from typing import Dict, List, Tuple


class ValidationResult:
    """Holds validation results."""

    def __init__(self):
        self.errors: List[str] = []
        self.warnings: List[str] = []
        self.info: List[str] = []
        self.passed_checks: List[str] = []

    def error(self, msg: str):
        self.errors.append(msg)

    def warning(self, msg: str):
        self.warnings.append(msg)

    def passed(self, msg: str):
        self.passed_checks.append(msg)

    @property
    def is_valid(self) -> bool:
        return len(self.errors) == 0

    def to_dict(self) -> Dict:
        return {
            "valid": self.is_valid,
            "errors": self.errors,
            "warnings": self.warnings,
            "passed": self.passed_checks,
            "summary": {
                "error_count": len(self.errors),
                "warning_count": len(self.warnings),
                "passed_count": len(self.passed_checks)
            }
        }


def parse_args() -> argparse.Namespace:
    """Parse command line arguments."""
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter
    )

    parser.add_argument(
        "skill_path",
        type=str,
        help="Path to skill folder"
    )

    parser.add_argument(
        "--strict",
        action="store_true",
        help="Treat warnings as errors"
    )

    parser.add_argument(
        "--json",
        action="store_true",
        help="Output as JSON"
    )

    return parser.parse_args()


def validate_folder_name(skill_path: Path, result: ValidationResult):
    """Validate skill folder name is kebab-case."""
    folder_name = skill_path.name

    if not re.match(r'^[a-z][a-z0-9-]*[a-z0-9]$', folder_name):
        result.error(f"Folder name '{folder_name}' must be kebab-case (lowercase, hyphens only)")
    else:
        result.passed("Folder name is valid kebab-case")


def validate_skill_md_exists(skill_path: Path, result: ValidationResult) -> bool:
    """Check SKILL.md exists."""
    skill_md = skill_path / "SKILL.md"

    if not skill_md.exists():
        result.error("Missing required SKILL.md file")
        return False

    result.passed("SKILL.md exists")
    return True


def parse_yaml_frontmatter(content: str) -> Tuple[Dict, str]:
    """Parse YAML frontmatter from markdown."""
    if not content.startswith('---'):
        return {}, content

    parts = content.split('---', 2)
    if len(parts) < 3:
        return {}, content

    frontmatter_text = parts[1].strip()
    body = parts[2].strip()

    # Simple YAML parsing (key: value)
    frontmatter = {}
    current_key = None
    current_value = []

    for line in frontmatter_text.split('\n'):
        if line.startswith('  ') and current_key:
            # Continuation of multiline value
            current_value.append(line.strip().lstrip('- '))
        else:
            # Save previous key
            if current_key:
                val = '\n'.join(current_value).strip()
                if val.startswith('|'):
                    val = val[1:].strip()
                frontmatter[current_key] = val

            # Parse new key
            if ':' in line:
                key, val = line.split(':', 1)
                current_key = key.strip()
                val = val.strip()
                if val and not val.startswith('|'):
                    current_value = [val]
                else:
                    current_value = []
            else:
                current_key = None
                current_value = []

    # Save last key
    if current_key:
        val = '\n'.join(current_value).strip()
        if val.startswith('|'):
            val = val[1:].strip()
        frontmatter[current_key] = val

    return frontmatter, body


def validate_frontmatter(skill_path: Path, result: ValidationResult):
    """Validate SKILL.md frontmatter."""
    skill_md = skill_path / "SKILL.md"
    content = skill_md.read_text(encoding='utf-8')

    frontmatter, body = parse_yaml_frontmatter(content)

    # Check required fields
    if not frontmatter.get('name'):
        result.error("Missing 'name' in frontmatter")
    else:
        name = frontmatter['name']
        # Name should be Title Case, not kebab-case
        if '-' in name and name.lower() == name:
            result.warning(f"Name '{name}' appears to be kebab-case, should be Title Case")
        else:
            result.passed("Name is present and formatted correctly")

    if not frontmatter.get('description'):
        result.error("Missing 'description' in frontmatter")
    else:
        desc = frontmatter['description']
        if len(desc) < 50:
            result.warning("Description is very short (< 50 chars). Consider adding trigger phrases.")
        elif 'WHEN TO USE' not in desc.upper():
            result.warning("Description missing 'WHEN TO USE' section with trigger phrases")
        else:
            result.passed("Description includes trigger phrases")

    # Check allowed-tools
    if 'allowed-tools' not in frontmatter:
        result.warning("No 'allowed-tools' specified. Consider adding for security.")
    else:
        result.passed("allowed-tools is specified")


def validate_structure(skill_path: Path, result: ValidationResult):
    """Validate skill folder structure."""
    # Check for recommended directories
    scripts_dir = skill_path / "scripts"
    refs_dir = skill_path / "references"
    examples_dir = skill_path / "examples"

    if scripts_dir.exists():
        py_files = list(scripts_dir.glob("*.py"))
        if py_files:
            result.passed(f"scripts/ contains {len(py_files)} Python file(s)")
        else:
            result.warning("scripts/ directory exists but has no .py files")

    if refs_dir.exists():
        ref_files = list(refs_dir.glob("*"))
        if ref_files:
            result.passed(f"references/ contains {len(ref_files)} file(s)")
        else:
            result.warning("references/ directory exists but is empty")

    if examples_dir.exists():
        result.passed("examples/ directory exists")


def validate_skill_md_content(skill_path: Path, result: ValidationResult):
    """Validate SKILL.md body content."""
    skill_md = skill_path / "SKILL.md"
    content = skill_md.read_text(encoding='utf-8')

    _, body = parse_yaml_frontmatter(content)

    # Check for key sections
    if '## Purpose' not in body and '## Overview' not in body:
        result.warning("SKILL.md missing Purpose or Overview section")
    else:
        result.passed("SKILL.md has Purpose/Overview section")

    if '## Instructions' not in body and '## Process' not in body:
        result.warning("SKILL.md missing Instructions section")
    else:
        result.passed("SKILL.md has Instructions section")

    # Check size
    word_count = len(body.split())
    if word_count > 2000:
        result.warning(f"SKILL.md body is {word_count} words. Consider moving content to references/")
    else:
        result.passed(f"SKILL.md body is appropriately sized ({word_count} words)")


def validate_skill(skill_path: Path, strict: bool = False) -> ValidationResult:
    """Main validation function."""
    result = ValidationResult()

    # Run all validations
    validate_folder_name(skill_path, result)

    if validate_skill_md_exists(skill_path, result):
        validate_frontmatter(skill_path, result)
        validate_skill_md_content(skill_path, result)

    validate_structure(skill_path, result)

    # In strict mode, warnings become errors
    if strict:
        result.errors.extend(result.warnings)
        result.warnings = []

    return result


def format_report(result: ValidationResult, skill_path: Path) -> str:
    """Format validation result as text report."""
    lines = []
    lines.append(f"Skill Validation Report: {skill_path.name}")
    lines.append("=" * 50)
    lines.append("")

    if result.is_valid:
        lines.append("Status: VALID")
    else:
        lines.append("Status: INVALID")

    lines.append("")

    if result.errors:
        lines.append("ERRORS:")
        for error in result.errors:
            lines.append(f"  - {error}")
        lines.append("")

    if result.warnings:
        lines.append("WARNINGS:")
        for warning in result.warnings:
            lines.append(f"  - {warning}")
        lines.append("")

    if result.passed_checks:
        lines.append("PASSED:")
        for passed in result.passed_checks:
            lines.append(f"  + {passed}")

    lines.append("")
    lines.append(f"Summary: {len(result.errors)} errors, {len(result.warnings)} warnings, {len(result.passed_checks)} passed")

    return '\n'.join(lines)


def main():
    """Main entry point."""
    args = parse_args()

    skill_path = Path(args.skill_path)

    if not skill_path.exists():
        print(f"Error: Skill path not found - {args.skill_path}", file=sys.stderr)
        sys.exit(1)

    if not skill_path.is_dir():
        print(f"Error: Path is not a directory - {args.skill_path}", file=sys.stderr)
        sys.exit(1)

    result = validate_skill(skill_path, strict=args.strict)

    if args.json:
        output = result.to_dict()
        output["skill_path"] = str(skill_path)
        print(json.dumps(output, indent=2))
    else:
        print(format_report(result, skill_path))

    sys.exit(0 if result.is_valid else 1)


if __name__ == "__main__":
    main()
