#!/usr/bin/env python3
"""
Migrate SKILL.md files to new structure:
1. Extract YAML frontmatter → skill.yaml
2. Strip frontmatter from SKILL.md
3. Create tools/ directory

Usage:
    python migrate-skill-structure.py --dry-run     # Preview changes
    python migrate-skill-structure.py               # Execute migration
    python migrate-skill-structure.py --verbose     # Verbose output
"""

import argparse
import re
import sys
from pathlib import Path
from typing import Optional

import yaml


def find_skill_files(base_path: Path) -> list[Path]:
    """Find all desktop/SKILL.md files."""
    skill_files = []

    for skill_md in base_path.rglob("desktop/SKILL.md"):
        # Skip archived skills
        if "99_archive" in str(skill_md):
            continue
        skill_files.append(skill_md)

    return sorted(skill_files)


def parse_frontmatter(content: str) -> tuple[Optional[dict], str]:
    """
    Parse YAML frontmatter from content.
    Returns (frontmatter_dict, remaining_content).
    """
    # Match frontmatter between --- delimiters
    pattern = r'^---\s*\n(.*?)\n---\s*\n(.*)$'
    match = re.match(pattern, content, re.DOTALL)

    if not match:
        return None, content

    frontmatter_text = match.group(1)
    remaining_content = match.group(2)

    try:
        frontmatter = yaml.safe_load(frontmatter_text)
        return frontmatter, remaining_content
    except yaml.YAMLError as e:
        print(f"  YAML parse error: {e}")
        return None, content


def generate_skill_yaml(frontmatter: dict) -> str:
    """Generate skill.yaml content from frontmatter."""
    # Use a custom dumper to preserve formatting
    result = "# Skill metadata (extracted from SKILL.md frontmatter)\n\n"

    # Required fields first
    if "name" in frontmatter:
        result += f"name: {frontmatter['name']}\n"

    if "description" in frontmatter:
        desc = frontmatter["description"]
        # Check if description is multi-line
        if "\n" in str(desc) or len(str(desc)) > 80:
            result += "description: |\n"
            for line in str(desc).strip().split("\n"):
                result += f"  {line}\n"
        else:
            # Single line - use quoted string if contains special chars
            if any(c in str(desc) for c in [":", "{", "}", "[", "]", ",", "#", "&", "*", "!", "|", ">", "'", '"', "%", "@", "`"]):
                result += f'description: "{desc}"\n'
            else:
                result += f"description: {desc}\n"

    result += "\n# Optional fields\n"

    # Optional fields
    if "allowed-tools" in frontmatter:
        tools = frontmatter["allowed-tools"]
        if isinstance(tools, str):
            # Parse comma-separated tools
            tool_list = [t.strip() for t in tools.split(",")]
        else:
            tool_list = tools

        result += "allowed-tools:\n"
        for tool in tool_list:
            result += f"  - {tool}\n"

    if "license" in frontmatter:
        result += f"\nlicense: {frontmatter['license']}\n"

    # Add triggers section (placeholder - can be extracted from description)
    result += "\n# triggers: []  # TODO: Extract from description\n"

    return result


def get_tool_stubs(frontmatter: dict) -> dict[str, str]:
    """
    Determine which tool stub files to create based on allowed-tools.
    Returns dict of {filename: content}.
    """
    stubs = {}

    if "allowed-tools" not in frontmatter:
        return stubs

    tools_str = frontmatter["allowed-tools"]
    if isinstance(tools_str, str):
        tools = [t.strip() for t in tools_str.split(",")]
    else:
        tools = tools_str

    # Map tools to stub files
    tool_mappings = {
        "mcp__firecrawl__*": "firecrawl",
        "mcp__perplexity__*": "perplexity",
        "mcp__notion__*": "notion",
        "mcp__chrome-devtools__*": "chrome-devtools",
    }

    claude_core_tools = {"Read", "Write", "Edit", "Bash", "Glob", "Grep"}
    webfetch_tools = {"WebFetch"}

    has_claude_core = False
    has_webfetch = False
    mcp_tools = set()

    for tool in tools:
        tool = tool.strip()

        # Check MCP tool patterns
        for pattern, stub_name in tool_mappings.items():
            if pattern.replace("*", "") in tool or tool == pattern:
                mcp_tools.add(stub_name)
                break
        else:
            # Check Claude core tools
            if tool in claude_core_tools:
                has_claude_core = True
            elif tool in webfetch_tools:
                has_webfetch = True

    # Generate stub content
    stub_template = """# {tool_name}

> TODO: Document tool usage for this skill

## Available Commands

- [ ] List commands

## Configuration

- [ ] Add configuration details

## Examples

- [ ] Add usage examples
"""

    for mcp_tool in mcp_tools:
        title = mcp_tool.replace("-", " ").title()
        stubs[f"{mcp_tool}.md"] = stub_template.format(tool_name=title)

    if has_claude_core:
        stubs["claude-core.md"] = stub_template.format(tool_name="Claude Core Tools (Read, Write, Edit, Bash, Glob, Grep)")

    if has_webfetch:
        stubs["webfetch.md"] = stub_template.format(tool_name="WebFetch")

    return stubs


def migrate_skill(skill_md_path: Path, dry_run: bool = True, verbose: bool = False) -> dict:
    """
    Migrate a single SKILL.md file.
    Returns status dict.
    """
    desktop_dir = skill_md_path.parent
    skill_yaml_path = desktop_dir / "skill.yaml"
    tools_dir = desktop_dir / "tools"

    status = {
        "path": str(skill_md_path),
        "success": False,
        "skill_yaml_created": False,
        "frontmatter_stripped": False,
        "tools_dir_created": False,
        "tool_stubs": [],
        "error": None
    }

    try:
        # Read original content
        content = skill_md_path.read_text(encoding="utf-8")

        # Parse frontmatter
        frontmatter, remaining_content = parse_frontmatter(content)

        if frontmatter is None:
            status["error"] = "No frontmatter found"
            return status

        # Generate skill.yaml content
        skill_yaml_content = generate_skill_yaml(frontmatter)

        # Get tool stubs
        tool_stubs = get_tool_stubs(frontmatter)
        status["tool_stubs"] = list(tool_stubs.keys())

        if verbose:
            print(f"\n  Frontmatter fields: {list(frontmatter.keys())}")
            print(f"  Tool stubs to create: {status['tool_stubs']}")

        if dry_run:
            print(f"  [DRY-RUN] Would create: {skill_yaml_path}")
            print(f"  [DRY-RUN] Would strip frontmatter from: {skill_md_path}")
            print(f"  [DRY-RUN] Would create directory: {tools_dir}")
            for stub_name in tool_stubs:
                print(f"  [DRY-RUN] Would create stub: {tools_dir / stub_name}")
            status["success"] = True
        else:
            # Create skill.yaml
            skill_yaml_path.write_text(skill_yaml_content, encoding="utf-8")
            status["skill_yaml_created"] = True

            # Strip frontmatter from SKILL.md
            skill_md_path.write_text(remaining_content.lstrip(), encoding="utf-8")
            status["frontmatter_stripped"] = True

            # Create tools/ directory
            tools_dir.mkdir(exist_ok=True)
            status["tools_dir_created"] = True

            # Create tool stubs
            for stub_name, stub_content in tool_stubs.items():
                stub_path = tools_dir / stub_name
                stub_path.write_text(stub_content, encoding="utf-8")

            status["success"] = True

    except Exception as e:
        status["error"] = str(e)

    return status


def main():
    parser = argparse.ArgumentParser(description="Migrate SKILL.md files to new structure")
    parser.add_argument("--dry-run", action="store_true", help="Preview changes without executing")
    parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
    parser.add_argument("--path", type=str, default=None, help="Base path to search (default: auto-detect)")
    args = parser.parse_args()

    # Find base path
    if args.path:
        base_path = Path(args.path)
    else:
        # Auto-detect from script location
        script_dir = Path(__file__).parent
        base_path = script_dir.parent / "custom-skills"

    if not base_path.exists():
        print(f"Error: Path not found: {base_path}")
        sys.exit(1)

    print(f"Searching for SKILL.md files in: {base_path}")
    print(f"Mode: {'DRY-RUN' if args.dry_run else 'EXECUTE'}")
    print("-" * 60)

    # Find all skill files
    skill_files = find_skill_files(base_path)
    print(f"Found {len(skill_files)} desktop/SKILL.md files\n")

    # Process each file
    results = {
        "total": len(skill_files),
        "success": 0,
        "failed": 0,
        "skill_yaml_created": 0,
        "tools_dirs_created": 0,
        "tool_stubs_created": 0
    }

    for i, skill_path in enumerate(skill_files, 1):
        rel_path = skill_path.relative_to(base_path)
        print(f"[{i}/{len(skill_files)}] Processing: {rel_path}")

        status = migrate_skill(skill_path, dry_run=args.dry_run, verbose=args.verbose)

        if status["success"]:
            results["success"] += 1
            if status["skill_yaml_created"] or args.dry_run:
                results["skill_yaml_created"] += 1
            if status["tools_dir_created"] or args.dry_run:
                results["tools_dirs_created"] += 1
            results["tool_stubs_created"] += len(status["tool_stubs"])
            print(f"  ✓ OK")
        else:
            results["failed"] += 1
            print(f"  ✗ FAILED: {status['error']}")

    # Summary
    print("\n" + "=" * 60)
    print("MIGRATION SUMMARY")
    print("=" * 60)
    print(f"Total files processed: {results['total']}")
    print(f"Successful: {results['success']}")
    print(f"Failed: {results['failed']}")
    print(f"skill.yaml files {'to create' if args.dry_run else 'created'}: {results['skill_yaml_created']}")
    print(f"tools/ directories {'to create' if args.dry_run else 'created'}: {results['tools_dirs_created']}")
    print(f"Tool stub files {'to create' if args.dry_run else 'created'}: {results['tool_stubs_created']}")

    if args.dry_run:
        print("\n[DRY-RUN] No files were modified. Run without --dry-run to execute.")

    return 0 if results["failed"] == 0 else 1


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