"""CLAUDE.md Auto-Sync Command for Empathy Framework

Syncs learned patterns from Empathy's pattern storage to Claude Code's
.claude/rules/empathy/ directory for native integration.

Usage:
    empathy sync-claude                    # One-time sync
    empathy sync-claude --watch           # Watch for changes
    empathy sync-claude --dry-run         # Show what would be synced

Output structure:
    .claude/rules/empathy/
    ├── bug-patterns.md          # From patterns/debugging/
    ├── security-decisions.md    # From patterns/security/
    ├── tech-debt-hotspots.md    # From patterns/tech_debt/
    └── coding-patterns.md       # General patterns

Copyright 2025 Smart AI Memory, LLC
Licensed under Fair Source 0.9
"""

import argparse
import json
import sys
import time
from datetime import datetime
from pathlib import Path
from typing import Any

# Output directory structure
CLAUDE_RULES_DIR = ".claude/rules/empathy"

# Pattern source directories
PATTERN_SOURCES = {
    "debugging": "bug-patterns.md",
    "security": "security-decisions.md",
    "tech_debt": "tech-debt-hotspots.md",
    "inspection": "coding-patterns.md",
}


def load_patterns_from_directory(pattern_dir: Path, pattern_type: str) -> list[dict]:
    """Load all pattern JSON files from a directory.

    Args:
        pattern_dir: Path to pattern directory
        pattern_type: Type of patterns (debugging, security, etc.)

    Returns:
        List of pattern dictionaries

    """
    patterns: list[dict[str, Any]] = []

    if not pattern_dir.exists():
        return patterns

    for json_file in pattern_dir.glob("*.json"):
        try:
            with open(json_file) as f:
                pattern = json.load(f)
                pattern["_source_file"] = str(json_file)
                pattern["_pattern_type"] = pattern_type
                patterns.append(pattern)
        except (json.JSONDecodeError, OSError) as e:
            print(f"Warning: Could not load {json_file}: {e}", file=sys.stderr)

    return patterns


def format_bug_patterns_markdown(patterns: list[dict]) -> str:
    """Format debugging patterns as Claude-compatible markdown.

    Args:
        patterns: List of bug pattern dictionaries

    Returns:
        Formatted markdown string

    """
    lines = [
        "---",
        "paths: **/*.py, **/*.js, **/*.ts",
        "---",
        "",
        "# Bug Patterns (Auto-generated by Empathy)",
        f"Last sync: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
        "",
        "These patterns help identify and fix common bugs based on your team's history.",
        "",
    ]

    # Group by error type
    by_type: dict[str, list[dict]] = {}
    for p in patterns:
        error_type = p.get("error_type", "unknown")
        if error_type not in by_type:
            by_type[error_type] = []
        by_type[error_type].append(p)

    for error_type, type_patterns in by_type.items():
        type_title = error_type.replace("_", " ").title()
        lines.append(f"## {type_title} Bugs")
        lines.append("")

        for p in type_patterns[:5]:  # Max 5 per type
            error_message = p.get("error_message", "Unknown error")
            root_cause = p.get("root_cause", "")
            fix_applied = p.get("fix_applied", "")
            pattern_id = p.get("pattern_id", "")

            lines.append(f"### When you see: `{error_message[:100]}`")
            if root_cause:
                lines.append(f"**Root cause:** {root_cause}")
            if fix_applied:
                lines.append(f"**Fix:** {fix_applied}")
            if pattern_id:
                lines.append(f"**Pattern ID:** {pattern_id}")
            lines.append("")

    return "\n".join(lines)


def format_security_decisions_markdown(patterns: list[dict]) -> str:
    """Format security decisions as Claude-compatible markdown."""
    lines = [
        "---",
        "paths: **/*.py, **/*.js, **/*.ts",
        "---",
        "",
        "# Security Decisions (Auto-generated by Empathy)",
        f"Last sync: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
        "",
        "Team security decisions and accepted risks. Reference these before flagging issues.",
        "",
    ]

    # Group by decision type
    by_status: dict[str, list[dict]] = {"ACCEPTED": [], "FALSE_POSITIVE": [], "DEFERRED": []}

    for p in patterns:
        status = p.get("status", "ACCEPTED")
        if status in by_status:
            by_status[status].append(p)

    if by_status["FALSE_POSITIVE"]:
        lines.append("## False Positives (Do Not Flag)")
        lines.append("")
        for p in by_status["FALSE_POSITIVE"][:10]:
            issue_type = p.get("issue_type", "unknown")
            rationale = p.get("rationale", "")
            decided_by = p.get("decided_by", "")
            lines.append(f"- **{issue_type}**: {rationale}")
            if decided_by:
                lines.append(f"  - Decided by: {decided_by}")
        lines.append("")

    if by_status["ACCEPTED"]:
        lines.append("## Accepted Risks")
        lines.append("")
        for p in by_status["ACCEPTED"][:10]:
            issue_type = p.get("issue_type", "unknown")
            rationale = p.get("rationale", "")
            lines.append(f"- **{issue_type}**: {rationale}")
        lines.append("")

    if by_status["DEFERRED"]:
        lines.append("## Deferred (To Address Later)")
        lines.append("")
        for p in by_status["DEFERRED"][:10]:
            issue_type = p.get("issue_type", "unknown")
            rationale = p.get("rationale", "")
            lines.append(f"- **{issue_type}**: {rationale}")
        lines.append("")

    return "\n".join(lines)


def format_tech_debt_markdown(patterns: list[dict]) -> str:
    """Format tech debt hotspots as Claude-compatible markdown."""
    lines = [
        "---",
        "paths: **/*",
        "---",
        "",
        "# Tech Debt Hotspots (Auto-generated by Empathy)",
        f"Last sync: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
        "",
        "Areas of the codebase with accumulated technical debt.",
        "",
    ]

    # Group by severity
    by_severity: dict[str, list[dict]] = {"critical": [], "high": [], "medium": [], "low": []}

    for p in patterns:
        # Get debt items from snapshot
        items = p.get("debt_items", [])
        for item in items:
            severity = item.get("severity", "medium")
            if severity in by_severity:
                by_severity[severity].append(item)

    for severity in ["critical", "high", "medium"]:
        if by_severity[severity]:
            lines.append(f"## {severity.upper()} Priority")
            lines.append("")
            for item in by_severity[severity][:10]:
                file_path = item.get("file", "")
                line = item.get("line", "")
                item_type = item.get("type", "")
                content = item.get("content", "")[:100]
                lines.append(f"- **{file_path}:{line}** ({item_type})")
                if content:
                    lines.append(f"  `{content}`")
            lines.append("")

    return "\n".join(lines)


def format_coding_patterns_markdown(patterns: list[dict]) -> str:
    """Format general coding patterns as Claude-compatible markdown."""
    lines = [
        "---",
        "paths: **/*",
        "---",
        "",
        "# Coding Patterns (Auto-generated by Empathy)",
        f"Last sync: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
        "",
        "Coding patterns and quality findings from automated inspection.",
        "",
    ]

    # Group by category
    by_category: dict[str, list[dict]] = {}

    for p in patterns:
        category = p.get("category", "general")
        if category not in by_category:
            by_category[category] = []
        by_category[category].append(p)

    for category, cat_patterns in by_category.items():
        category_title = category.replace("_", " ").title()
        lines.append(f"## {category_title}")
        lines.append("")

        for p in cat_patterns[:10]:
            description = p.get("description", "")
            recommendation = p.get("recommendation", "")

            if description:
                lines.append(f"- {description}")
            if recommendation:
                lines.append(f"  **Recommendation:** {recommendation}")

        lines.append("")

    return "\n".join(lines)


def sync_patterns(
    project_root: Path,
    dry_run: bool = False,
    verbose: bool = False,
) -> dict[str, Any]:
    """Sync patterns to .claude/rules/empathy/ directory.

    Args:
        project_root: Project root directory
        dry_run: If True, don't write files
        verbose: If True, print detailed output

    Returns:
        Summary of sync operation

    """
    patterns_dir = project_root / "patterns"
    output_dir = project_root / CLAUDE_RULES_DIR

    results: dict[str, Any] = {
        "synced": [],
        "skipped": [],
        "errors": [],
        "total_patterns": 0,
    }

    if not patterns_dir.exists():
        if verbose:
            print(f"No patterns directory found at {patterns_dir}")
        return results

    # Create output directory
    if not dry_run:
        output_dir.mkdir(parents=True, exist_ok=True)

    # Process each pattern type
    formatters = {
        "debugging": format_bug_patterns_markdown,
        "security": format_security_decisions_markdown,
        "tech_debt": format_tech_debt_markdown,
        "inspection": format_coding_patterns_markdown,
    }

    for pattern_type, output_file in PATTERN_SOURCES.items():
        source_dir = patterns_dir / pattern_type
        patterns = load_patterns_from_directory(source_dir, pattern_type)

        if not patterns:
            if verbose:
                print(f"No {pattern_type} patterns found")
            results["skipped"].append(pattern_type)
            continue

        results["total_patterns"] += len(patterns)

        # Format patterns
        formatter = formatters.get(pattern_type, format_coding_patterns_markdown)
        markdown_content = formatter(patterns)

        # Write output
        output_path = output_dir / output_file

        if dry_run:
            print(f"Would write {len(patterns)} patterns to {output_path}")
            if verbose:
                print(f"--- {output_file} ---")
                print(
                    (
                        markdown_content[:500] + "..."
                        if len(markdown_content) > 500
                        else markdown_content
                    ),
                )
                print()
        else:
            try:
                with open(output_path, "w") as f:
                    f.write(markdown_content)
                results["synced"].append(
                    {
                        "type": pattern_type,
                        "file": str(output_path),
                        "patterns": len(patterns),
                    },
                )
                if verbose:
                    print(f"Synced {len(patterns)} {pattern_type} patterns to {output_path}")
            except OSError as e:
                results["errors"].append(f"{pattern_type}: {e}")
                if verbose:
                    print(f"Error writing {output_path}: {e}", file=sys.stderr)

    return results


def watch_and_sync(project_root: Path, interval: int = 30, verbose: bool = False):
    """Watch patterns directory and sync on changes.

    Args:
        project_root: Project root directory
        interval: Check interval in seconds
        verbose: Verbose output

    """
    print(f"Watching for pattern changes (every {interval}s)...")
    print("Press Ctrl+C to stop")

    patterns_dir = project_root / "patterns"
    last_mtime = 0.0

    try:
        while True:
            # Check for changes
            current_mtime = 0.0
            if patterns_dir.exists():
                for json_file in patterns_dir.rglob("*.json"):
                    file_mtime = json_file.stat().st_mtime
                    current_mtime = max(current_mtime, file_mtime)

            if current_mtime > last_mtime:
                if last_mtime > 0:
                    print(f"\n[{datetime.now().strftime('%H:%M:%S')}] Changes detected, syncing...")
                    results = sync_patterns(project_root, verbose=verbose)
                    print(f"Synced {results['total_patterns']} patterns")
                else:
                    # Initial sync
                    results = sync_patterns(project_root, verbose=verbose)
                    print(f"Initial sync: {results['total_patterns']} patterns")
                last_mtime = current_mtime

            time.sleep(interval)

    except KeyboardInterrupt:
        print("\nStopped watching")


def main():
    """Main CLI entry point."""
    parser = argparse.ArgumentParser(
        prog="empathy sync-claude",
        description="Sync Empathy patterns to .claude/rules/empathy/",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  empathy sync-claude                    # Sync patterns once
  empathy sync-claude --watch            # Watch and auto-sync
  empathy sync-claude --dry-run          # Preview without writing
  empathy sync-claude --verbose          # Show detailed output

Output structure:
  .claude/rules/empathy/
  ├── bug-patterns.md          # From patterns/debugging/
  ├── security-decisions.md    # From patterns/security/
  ├── tech-debt-hotspots.md    # From patterns/tech_debt/
  └── coding-patterns.md       # From patterns/inspection/
        """,
    )

    parser.add_argument(
        "--project-root",
        "-p",
        type=Path,
        default=Path.cwd(),
        help="Project root directory (default: current directory)",
    )
    parser.add_argument(
        "--watch",
        "-w",
        action="store_true",
        help="Watch for changes and auto-sync",
    )
    parser.add_argument(
        "--interval",
        "-i",
        type=int,
        default=30,
        help="Watch interval in seconds (default: 30)",
    )
    parser.add_argument(
        "--dry-run",
        "-n",
        action="store_true",
        help="Show what would be synced without writing files",
    )
    parser.add_argument(
        "--verbose",
        "-v",
        action="store_true",
        help="Verbose output",
    )

    args = parser.parse_args()

    project_root = args.project_root.resolve()

    if args.verbose:
        print(f"Project root: {project_root}")
        print(f"Patterns dir: {project_root / 'patterns'}")
        print(f"Output dir: {project_root / CLAUDE_RULES_DIR}")
        print()

    if args.watch:
        watch_and_sync(project_root, args.interval, args.verbose)
    else:
        results = sync_patterns(project_root, args.dry_run, args.verbose)

        if args.dry_run:
            print(f"\nDry run complete: {results['total_patterns']} patterns would be synced")
        else:
            if results["synced"]:
                print(f"\n✓ Synced {results['total_patterns']} patterns to {CLAUDE_RULES_DIR}/")
                for item in results["synced"]:
                    print(f"  - {item['type']}: {item['patterns']} patterns")
            elif results["skipped"]:
                print("No patterns to sync")

            if results["errors"]:
                print("\nErrors:", file=sys.stderr)
                for error in results["errors"]:
                    print(f"  - {error}", file=sys.stderr)
                sys.exit(1)


if __name__ == "__main__":
    main()
