#!/usr/bin/env python3
"""
Auto-Fix Script
Applies safe fixes to Claude Code configuration with backup.
"""

import json
import shutil
import sys
from datetime import datetime
from pathlib import Path

# serverInstructions templates for common MCP servers
SERVER_INSTRUCTIONS = {
    "playwright": "Browser automation for web interaction. Use for: SEO audits, page analysis, screenshots, form testing, Core Web Vitals. Keywords: browser, page, screenshot, click, navigate, DOM, selector",
    "puppeteer": "Chrome automation for web testing. Use for: SEO audits, page rendering, JavaScript site testing. Keywords: browser, chrome, headless, screenshot, page",
    "notion": "Notion workspace integration. Use for: saving research, documentation, project notes, knowledge base. Keywords: notion, page, database, wiki, notes, save",
    "github": "GitHub repository management. Use for: commits, PRs, issues, code review. Keywords: git, github, commit, pull request, issue, repository",
    "postgres": "PostgreSQL database queries. Use for: data analysis, SQL queries, analytics. Keywords: sql, query, database, table, select, analytics",
    "postgresql": "PostgreSQL database queries. Use for: data analysis, SQL queries, analytics. Keywords: sql, query, database, table, select, analytics",
    "bigquery": "Google BigQuery for large-scale analysis. Use for: analytics queries, data warehouse. Keywords: bigquery, sql, analytics, data warehouse",
    "firecrawl": "Web scraping and crawling. Use for: site crawling, content extraction, competitor analysis. Keywords: crawl, scrape, extract, spider, sitemap",
    "slack": "Slack workspace integration. Use for: messages, notifications, team communication. Keywords: slack, message, channel, notification",
    "linear": "Linear issue tracking. Use for: issue management, project tracking. Keywords: linear, issue, task, project, sprint",
    "memory": "Persistent memory across sessions. Use for: storing preferences, context recall. Keywords: remember, memory, store, recall",
    "filesystem": "Local file operations. Use for: file reading/writing, directory management. Keywords: file, directory, read, write, path",
    "chrome-devtools": "Chrome DevTools for debugging. Use for: GTM debugging, network analysis, console logs. Keywords: devtools, chrome, debug, network, console",
}


class AutoFixer:
    def __init__(self, dry_run: bool = True):
        self.dry_run = dry_run
        self.fixes = []
        self.backup_dir = Path.home() / ".claude" / "backups" / datetime.now().strftime("%Y%m%d_%H%M%S")

    def backup_file(self, path: Path) -> bool:
        """Create backup before modifying."""
        if not path.exists():
            return True

        try:
            backup_path = self.backup_dir / path.relative_to(Path.home())
            backup_path.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(path, backup_path)
            return True
        except Exception as e:
            print(f"Warning: Could not backup {path}: {e}", file=sys.stderr)
            return False

    def fix_mcp_instructions(self, settings_path: Path) -> list:
        """Add serverInstructions to MCP servers."""
        fixes = []

        try:
            with open(settings_path) as f:
                settings = json.load(f)
        except (json.JSONDecodeError, IOError) as e:
            return [f"Error reading {settings_path}: {e}"]

        servers = settings.get("mcpServers", {})
        modified = False

        for name, config in servers.items():
            if not isinstance(config, dict):
                continue

            if "serverInstructions" in config:
                continue

            # Find matching template
            instructions = None
            name_lower = name.lower()
            for key, template in SERVER_INSTRUCTIONS.items():
                if key in name_lower:
                    instructions = template
                    break

            if not instructions:
                instructions = f"External tool: {name}. Use when this functionality is needed."

            if self.dry_run:
                fixes.append(f"[DRY RUN] Would add serverInstructions to '{name}'")
            else:
                config["serverInstructions"] = instructions
                modified = True
                fixes.append(f"Added serverInstructions to '{name}'")

        if modified and not self.dry_run:
            self.backup_file(settings_path)
            with open(settings_path, 'w') as f:
                json.dump(settings, f, indent=2)

        return fixes

    def fix_command_frontmatter(self, cmd_path: Path) -> str | None:
        """Add frontmatter to command missing it."""
        try:
            content = cmd_path.read_text()
        except IOError:
            return None

        if content.startswith('---'):
            return None

        new_content = f'''---
description: {cmd_path.stem.replace('-', ' ').title()} command
---

{content}'''

        if self.dry_run:
            return f"[DRY RUN] Would add frontmatter to {cmd_path.name}"

        self.backup_file(cmd_path)
        cmd_path.write_text(new_content)
        return f"Added frontmatter to {cmd_path.name}"

    def run(self) -> dict:
        """Apply all fixes."""
        results = {"applied": [], "skipped": [], "errors": []}

        # Fix MCP settings
        settings_paths = [
            Path.home() / ".claude" / "settings.json",
            Path.cwd() / ".claude" / "settings.json"
        ]

        for path in settings_paths:
            if path.exists():
                fixes = self.fix_mcp_instructions(path)
                results["applied"].extend(fixes)

        # Fix commands without frontmatter
        cmd_dirs = [
            Path.home() / ".claude" / "commands",
            Path.cwd() / ".claude" / "commands"
        ]

        for cmd_dir in cmd_dirs:
            if cmd_dir.exists():
                for cmd_file in cmd_dir.glob("*.md"):
                    fix = self.fix_command_frontmatter(cmd_file)
                    if fix:
                        results["applied"].append(fix)

        return results


def main():
    import argparse

    parser = argparse.ArgumentParser(description="Auto-fix Claude Code settings")
    parser.add_argument("--apply", action="store_true", help="Apply fixes (default is dry-run)")
    args = parser.parse_args()

    fixer = AutoFixer(dry_run=not args.apply)
    results = fixer.run()

    print(json.dumps(results, indent=2))

    if fixer.dry_run:
        print("\n[DRY RUN] No changes applied. Use --apply to apply fixes.", file=sys.stderr)
    else:
        print(f"\n[APPLIED] {len(results['applied'])} fixes.", file=sys.stderr)
        if fixer.backup_dir.exists():
            print(f"Backups: {fixer.backup_dir}", file=sys.stderr)

    return 0


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