#!/usr/bin/env python3
"""
SKILL.md Enhancement Script (Local - Using CLI Coding Agents)
Uses a local coding agent CLI (Claude Code, Codex CLI, Copilot CLI, OpenCode CLI)
to enhance SKILL.md, then reports back. No API key needed.

Usage:
    # Headless mode (default - runs in foreground, waits for completion)
    skill-seekers enhance output/react/

    # Background mode (runs in background, returns immediately)
    skill-seekers enhance output/react/ --background

    # Disable force mode (enable confirmations)
    skill-seekers enhance output/react/ --no-force

    # Daemon mode (persistent background process)
    skill-seekers enhance output/react/ --daemon

    # Interactive terminal mode
    skill-seekers enhance output/react/ --interactive-enhancement

    # Use a different local coding agent
    skill-seekers enhance output/react/ --agent codex
    skill-seekers enhance output/react/ --agent copilot
    skill-seekers enhance output/react/ --agent opencode

    # Custom agent command (advanced)
    skill-seekers enhance output/react/ --agent custom --agent-cmd "my-agent --prompt {prompt_file}"

Modes:
    - headless: Runs local CLI directly, BLOCKS until done (default)
    - background: Runs local CLI in background, returns immediately
    - daemon: Runs as persistent background process with monitoring
    - terminal: Opens new terminal window (interactive)

Terminal Selection:
    The script automatically detects which terminal app to use:
    1. SKILL_SEEKER_TERMINAL env var (highest priority)
       Example: export SKILL_SEEKER_TERMINAL="Ghostty"
    2. TERM_PROGRAM env var (current terminal)
    3. Terminal.app (fallback)

    Supported terminals: Ghostty, iTerm, Terminal, WezTerm
"""

import json
import os
import shlex
import shutil
import subprocess
import sys
import tempfile
import threading
import time
from datetime import datetime
from pathlib import Path

import contextlib

from skill_seekers.cli.constants import LOCAL_CONTENT_LIMIT, LOCAL_PREVIEW_LIMIT
from skill_seekers.cli.utils import read_reference_files


def detect_terminal_app():
    """Detect which terminal app to use with cascading priority.

    Priority order:
        1. SKILL_SEEKER_TERMINAL environment variable (explicit user preference)
        2. TERM_PROGRAM environment variable (inherit current terminal)
        3. Terminal.app (fallback default)

    Returns:
        tuple: (terminal_app_name, detection_method)
            - terminal_app_name (str): Name of terminal app to launch (e.g., "Ghostty", "Terminal")
            - detection_method (str): How the terminal was detected (for logging)

    Examples:
        >>> os.environ['SKILL_SEEKER_TERMINAL'] = 'Ghostty'
        >>> detect_terminal_app()
        ('Ghostty', 'SKILL_SEEKER_TERMINAL')

        >>> os.environ['TERM_PROGRAM'] = 'iTerm.app'
        >>> detect_terminal_app()
        ('iTerm', 'TERM_PROGRAM')
    """
    # Map TERM_PROGRAM values to macOS app names
    TERMINAL_MAP = {
        "Apple_Terminal": "Terminal",
        "iTerm.app": "iTerm",
        "ghostty": "Ghostty",
        "WezTerm": "WezTerm",
    }

    # Priority 1: Check SKILL_SEEKER_TERMINAL env var (explicit preference)
    preferred_terminal = os.environ.get("SKILL_SEEKER_TERMINAL", "").strip()
    if preferred_terminal:
        return preferred_terminal, "SKILL_SEEKER_TERMINAL"

    # Priority 2: Check TERM_PROGRAM (inherit current terminal)
    term_program = os.environ.get("TERM_PROGRAM", "").strip()
    if term_program and term_program in TERMINAL_MAP:
        return TERMINAL_MAP[term_program], "TERM_PROGRAM"

    # Priority 3: Fallback to Terminal.app
    if term_program:
        # TERM_PROGRAM is set but unknown
        return "Terminal", f"unknown TERM_PROGRAM ({term_program})"
    else:
        # No TERM_PROGRAM set
        return "Terminal", "default"


AGENT_PRESETS = {
    "claude": {
        "display_name": "Claude Code",
        "command": ["claude", "{prompt_file}"],
        "supports_skip_permissions": True,
    },
    "codex": {
        "display_name": "OpenAI Codex CLI",
        "command": ["codex", "exec", "--full-auto", "--skip-git-repo-check", "-"],
        "supports_skip_permissions": False,
    },
    "copilot": {
        "display_name": "GitHub Copilot CLI",
        "command": ["gh", "copilot", "chat"],
        "supports_skip_permissions": False,
    },
    "opencode": {
        "display_name": "OpenCode CLI",
        "command": ["opencode"],
        "supports_skip_permissions": False,
    },
    "kimi": {
        "display_name": "Kimi Code CLI",
        "command": ["kimi", "--print", "--input-format", "text", "--work-dir", "{skill_dir}"],
        "supports_skip_permissions": False,
        "uses_stdin": True,
    },
}


def _normalize_agent_name(agent_name: str) -> str:
    if not agent_name:
        return "claude"
    normalized = agent_name.strip().lower()
    aliases = {
        "claude-code": "claude",
        "claude_code": "claude",
        "codex-cli": "codex",
        "copilot-cli": "copilot",
        "open-code": "opencode",
        "open_code": "opencode",
        "kimi-cli": "kimi",
    }
    return aliases.get(normalized, normalized)


class LocalSkillEnhancer:
    def __init__(self, skill_dir, force=True, agent=None, agent_cmd=None):
        """Initialize enhancer.

        Args:
            skill_dir: Path to skill directory
            force: If True, skip all confirmations (default: True, use --no-force to disable)
            agent: Local coding agent identifier (claude, codex, copilot, opencode, custom)
            agent_cmd: Override command template (use {prompt_file} placeholder or stdin)
        """
        self.skill_dir = Path(skill_dir)
        self.references_dir = self.skill_dir / "references"
        self.skill_md_path = self.skill_dir / "SKILL.md"
        self.force = force
        self.status_file = self.skill_dir / ".enhancement_status.json"
        self.agent, self.agent_cmd, self.agent_display = self._resolve_agent(agent, agent_cmd)

    def _validate_custom_command(self, cmd_template: str) -> None:
        """Validate custom command template for basic safety and executability."""
        dangerous_chars = [";", "&", "|", "$", "`", "\n", "\r"]
        if any(char in cmd_template for char in dangerous_chars):
            raise ValueError(
                f"Custom command contains dangerous shell characters. Command: {cmd_template}"
            )

        try:
            cmd_parts = shlex.split(cmd_template)
        except ValueError as exc:
            raise ValueError(f"Invalid command template: {exc}") from exc

        if not cmd_parts:
            raise ValueError("Custom command is empty.")

        executable = cmd_parts[0]
        if "/" in executable:
            executable_path = Path(executable)
            if not executable_path.is_file():
                raise ValueError(f"Custom command executable not found: {executable}")
        else:
            if not shutil.which(executable):
                raise ValueError(f"Executable '{executable}' not found in PATH")

    def _resolve_agent(self, agent, agent_cmd):
        # Priority: explicit param > ExecutionContext > env var > default
        try:
            from skill_seekers.cli.execution_context import ExecutionContext

            ctx = ExecutionContext.get()
            ctx_agent = ctx.enhancement.agent or ""
            ctx_cmd = ctx.enhancement.agent_cmd or ""
        except Exception:
            ctx_agent = ""
            ctx_cmd = ""

        env_agent = os.environ.get("SKILL_SEEKER_AGENT", "").strip()
        env_cmd = os.environ.get("SKILL_SEEKER_AGENT_CMD", "").strip()

        agent_name = _normalize_agent_name(agent or ctx_agent or env_agent or "claude")
        cmd_override = agent_cmd or ctx_cmd or env_cmd or None

        if agent_name == "custom":
            if not cmd_override:
                raise ValueError(
                    "Custom agent requires --agent-cmd or SKILL_SEEKER_AGENT_CMD to be set."
                )
            self._validate_custom_command(cmd_override)
            display_name = "Custom CLI Agent"
            return agent_name, cmd_override, display_name

        if agent_name not in AGENT_PRESETS:
            available = ", ".join(sorted(AGENT_PRESETS.keys()))
            raise ValueError(
                f"Unknown agent '{agent_name}'. Choose one of: {available} or use --agent custom."
            )

        display_name = AGENT_PRESETS[agent_name]["display_name"]
        return agent_name, cmd_override, display_name

    def _build_agent_command(self, prompt_file, include_permissions_flag):
        if self.agent_cmd:
            cmd_parts = shlex.split(self.agent_cmd)
            supports_skip_permissions = False
        else:
            preset = AGENT_PRESETS[self.agent]
            cmd_parts = list(preset["command"])
            supports_skip_permissions = preset.get("supports_skip_permissions", False)

        if (
            include_permissions_flag
            and supports_skip_permissions
            and "--dangerously-skip-permissions" not in cmd_parts
        ):
            cmd_parts.insert(1, "--dangerously-skip-permissions")

        uses_prompt_file = False
        for idx, arg in enumerate(cmd_parts):
            if "{prompt_file}" in arg:
                cmd_parts[idx] = arg.replace("{prompt_file}", prompt_file)
                uses_prompt_file = True
            if "{skill_dir}" in arg:
                cmd_parts[idx] = arg.replace("{skill_dir}", str(self.skill_dir.resolve()))

        return cmd_parts, uses_prompt_file

    def _format_agent_command(self, prompt_file, include_permissions_flag):
        cmd_parts, uses_prompt_file = self._build_agent_command(
            prompt_file, include_permissions_flag
        )
        cmd_str = shlex.join(cmd_parts)
        if uses_prompt_file:
            return cmd_str
        return f"cat {shlex.quote(prompt_file)} | {cmd_str}"

    def _run_agent_command(self, prompt_file, timeout, include_permissions_flag, quiet=False):
        cmd_parts, uses_prompt_file = self._build_agent_command(
            prompt_file, include_permissions_flag
        )

        if not quiet:
            cmd_display = self._format_agent_command(prompt_file, include_permissions_flag)
            print(f"   Command: {cmd_display}")

        try:
            if uses_prompt_file:
                return (
                    subprocess.run(
                        cmd_parts,
                        capture_output=True,
                        text=True,
                        timeout=timeout,
                        cwd=str(self.skill_dir),
                    ),
                    None,
                )

            prompt_text = Path(prompt_file).read_text(encoding="utf-8")
            return (
                subprocess.run(
                    cmd_parts,
                    capture_output=True,
                    text=True,
                    timeout=timeout,
                    cwd=str(self.skill_dir),
                    input=prompt_text,
                ),
                None,
            )
        except FileNotFoundError:
            return None, f"Command not found: {cmd_parts[0]}"
        except Exception as e:
            return None, str(e)

    def summarize_reference(self, content: str, target_ratio: float = 0.3) -> str:
        """Intelligently summarize reference content to reduce size.

        Strategy:
        1. Keep first 20% (introduction/overview)
        2. Extract code blocks (prioritize examples)
        3. Keep headings and their first paragraph
        4. Skip repetitive content

        Args:
            content: Full reference content
            target_ratio: Target size as ratio of original (0.3 = 30%)

        Returns:
            Summarized content
        """
        lines = content.split("\n")

        # Priority 1: Keep introduction (first 20%)
        intro_lines = int(len(lines) * 0.2)

        # Ensure intro doesn't cut inside a code block
        in_block = False
        safe_end = 0
        for i in range(intro_lines):
            if lines[i].strip().startswith("```"):
                in_block = not in_block
            if not in_block:
                safe_end = i + 1
        intro_lines = safe_end
        result_lines = lines[:intro_lines]

        # Priority 2: Extract code blocks
        in_code_block = False
        code_blocks = []
        current_block = []
        block_start_idx = 0

        for i, line in enumerate(lines[intro_lines:], start=intro_lines):
            if line.strip().startswith("```"):
                if in_code_block:
                    # End of code block - add closing ``` and save
                    current_block.append(line)
                    code_blocks.append((block_start_idx, current_block))
                    current_block = []
                    in_code_block = False
                else:
                    # Start of code block
                    in_code_block = True
                    block_start_idx = i
                    current_block = [line]
            elif in_code_block:
                current_block.append(line)

        # Combine: intro + code blocks + headings with token budget
        result = result_lines.copy()
        # Budget is target_ratio of original content length
        content_chars = len(content)
        max_chars = int(content_chars * target_ratio)
        current_chars = sum(len(line) for line in result)

        # Priority 2: Add code blocks first (prioritize code examples) - no arbitrary limit
        for _idx, block in code_blocks:
            block_chars = sum(len(line) for line in block) + 1  # +1 for blank line
            if current_chars + block_chars > max_chars:
                break
            result.append("")  # Add blank line before code block
            result.extend(block)
            current_chars += block_chars

        # Priority 3: Keep headings with first paragraph
        i = intro_lines
        headings_added = 0
        while i < len(lines) and headings_added < 10:
            line = lines[i]
            if line.startswith("#"):
                # Found heading - keep it and next 3 lines
                chunk = lines[i : min(i + 4, len(lines))]
                chunk_chars = sum(len(line_text) for line_text in chunk)
                if current_chars + chunk_chars > max_chars:
                    break
                result.extend(chunk)
                headings_added += 1
                current_chars += chunk_chars
                i += 4
            else:
                i += 1

        result.append("\n\n[Content intelligently summarized - full details in reference files]")

        return "\n".join(result)

    def create_enhancement_prompt(self, use_summarization=False, summarization_ratio=0.3):
        """Create the prompt file for a local coding agent

        Args:
            use_summarization: If True, apply smart summarization to reduce size
            summarization_ratio: Target size ratio when summarizing (0.3 = 30%)
        """

        # Read reference files (with enriched metadata)
        references = read_reference_files(
            self.skill_dir, max_chars=LOCAL_CONTENT_LIMIT, preview_limit=LOCAL_PREVIEW_LIMIT
        )

        if not references:
            print("❌ No reference files found")
            return None

        # Analyze sources
        sources_found = set()
        for metadata in references.values():
            sources_found.add(metadata["source"])

        # Calculate total size
        total_ref_size = sum(meta["size"] for meta in references.values())

        # Apply summarization if requested or if content is too large
        if use_summarization or total_ref_size > 30000:
            if not use_summarization:
                print(f"  ⚠️  Large skill detected ({total_ref_size:,} chars)")
                print(
                    f"  📊 Applying smart summarization (target: {int(summarization_ratio * 100)}% of original)"
                )
                print()

            # Summarize each reference
            for _filename, metadata in references.items():
                summarized = self.summarize_reference(metadata["content"], summarization_ratio)
                metadata["content"] = summarized
                metadata["size"] = len(summarized)

            new_size = sum(meta["size"] for meta in references.values())
            print(
                f"  ✓ Reduced from {total_ref_size:,} to {new_size:,} chars ({int(new_size / total_ref_size * 100)}%)"
            )
            print()

        # Read current SKILL.md
        current_skill_md = ""
        if self.skill_md_path.exists():
            current_skill_md = self.skill_md_path.read_text(encoding="utf-8")

        # Analyze conflicts if present
        has_conflicts = any("conflicts" in meta["path"] for meta in references.values())

        # Build prompt with multi-source awareness
        prompt = f"""I need you to enhance the SKILL.md file for the {self.skill_dir.name} skill.

SKILL OVERVIEW:
- Name: {self.skill_dir.name}
- Source Types: {", ".join(sorted(sources_found))}
- Multi-Source: {"Yes" if len(sources_found) > 1 else "No"}
- Conflicts Detected: {"Yes - see conflicts.md in references" if has_conflicts else "No"}

CURRENT SKILL.MD:
{"-" * 60}
{current_skill_md if current_skill_md else "(No existing SKILL.md - create from scratch)"}
{"-" * 60}

SOURCE ANALYSIS:
{"-" * 60}
This skill combines knowledge from {len(sources_found)} source type(s):

"""

        # Group references by (source_type, repo_id) for multi-source support
        by_source = {}
        for filename, metadata in references.items():
            source = metadata["source"]
            repo_id = metadata.get("repo_id")  # None for single-source
            key = (source, repo_id) if repo_id else (source, None)

            if key not in by_source:
                by_source[key] = []
            by_source[key].append((filename, metadata))

        # Add source breakdown with repo identity
        for source, repo_id in sorted(by_source.keys()):
            files = by_source[(source, repo_id)]
            if repo_id:
                prompt += f"\n**{source.upper()} - {repo_id} ({len(files)} file(s))**\n"
            else:
                prompt += f"\n**{source.upper()} ({len(files)} file(s))**\n"
            for filename, metadata in files[:5]:  # Top 5 per source
                prompt += f"- {filename} (confidence: {metadata['confidence']}, {metadata['size']:,} chars)\n"
            if len(files) > 5:
                prompt += f"- ... and {len(files) - 5} more\n"

        prompt += f"""
{"-" * 60}

REFERENCE DOCUMENTATION:
{"-" * 60}
"""

        # Add references grouped by (source, repo_id) with metadata
        for source, repo_id in sorted(by_source.keys()):
            if repo_id:
                prompt += f"\n### {source.upper()} SOURCES - {repo_id}\n\n"
            else:
                prompt += f"\n### {source.upper()} SOURCES\n\n"

            for filename, metadata in by_source[(source, repo_id)]:
                # Further limit per-file to 12K to be safe
                content = metadata["content"]
                max_per_file = 12000
                if len(content) > max_per_file:
                    content = content[:max_per_file] + "\n\n[Content truncated for size...]"

                prompt += f"\n#### {filename}\n"
                if repo_id:
                    prompt += f"*Source: {metadata['source']} ({repo_id}), Confidence: {metadata['confidence']}*\n\n"
                else:
                    prompt += (
                        f"*Source: {metadata['source']}, Confidence: {metadata['confidence']}*\n\n"
                    )
                prompt += f"{content}\n"

        prompt += f"""
{"-" * 60}

REFERENCE PRIORITY (when sources differ):
1. **Code patterns (codebase_analysis)**: Ground truth - what the code actually does
2. **Official documentation**: Intended API and usage patterns
3. **GitHub issues**: Real-world usage and known problems
4. **PDF documentation**: Additional context and tutorials

MULTI-REPOSITORY HANDLING:
"""

        # Detect multiple repos from same source type
        repo_ids = set()
        for metadata in references.values():
            if metadata.get("repo_id"):
                repo_ids.add(metadata["repo_id"])

        if len(repo_ids) > 1:
            prompt += f"""
⚠️ MULTIPLE REPOSITORIES DETECTED: {", ".join(sorted(repo_ids))}

This skill combines codebase analysis from {len(repo_ids)} different repositories.
Each repo has its own ARCHITECTURE.md, patterns, examples, and configuration.

When synthesizing:
- Clearly identify which content comes from which repo
- Compare and contrast patterns across repos (e.g., "httpx uses Strategy pattern 50 times, httpcore uses it 32 times")
- Highlight relationships (e.g., "httpx is a client library built on top of httpcore")
- Present examples from BOTH repos to show different use cases
- If repos serve different purposes, explain when to use each
"""
        else:
            prompt += "\nSingle repository - standard synthesis applies.\n"

        prompt += """

YOUR TASK:
Create an EXCELLENT SKILL.md file that synthesizes knowledge from multiple sources.

Requirements:
1. **Multi-Source Synthesis**
   - Acknowledge that this skill combines multiple sources
   - Highlight agreements between sources (builds confidence)
   - Note discrepancies transparently (if present)
   - Use source priority when synthesizing conflicting information

2. **Clear "When to Use This Skill" section**
   - Be SPECIFIC about trigger conditions
   - List concrete use cases
   - Include perspective from both docs AND real-world usage (if GitHub/codebase data available)

3. **Excellent Quick Reference section**
   - Extract 5-10 of the BEST, most practical code examples
   - Prefer examples from HIGH CONFIDENCE sources first
   - If code examples exist from codebase analysis, prioritize those (real usage)
   - If docs examples exist, include those too (official patterns)
   - Choose SHORT, clear examples (5-20 lines max)
   - Use proper language tags (cpp, python, javascript, json, etc.)
   - Add clear descriptions noting the source (e.g., "From official docs" or "From codebase")

4. **Detailed Reference Files description**
   - Explain what's in each reference file
   - Note the source type and confidence level
   - Help users navigate multi-source documentation

5. **Practical "Working with This Skill" section**
   - Clear guidance for beginners, intermediate, and advanced users
   - Navigation tips for multi-source references
   - How to resolve conflicts if present

6. **Key Concepts section** (if applicable)
   - Explain core concepts
   - Define important terminology
   - Reconcile differences between sources if needed

7. **Conflict Handling** (if conflicts detected)
   - Add a "Known Discrepancies" section
   - Explain major conflicts transparently
   - Provide guidance on which source to trust in each case

IMPORTANT:
- Extract REAL examples from the reference docs above
- Prioritize HIGH CONFIDENCE sources when synthesizing
- Note source attribution when helpful (e.g., "Official docs say X, but codebase shows Y")
- Make discrepancies transparent, not hidden
- Prioritize SHORT, clear examples
- Make it actionable and practical
- Keep the frontmatter (---\\nname: ...\\n---) intact
- Use proper markdown formatting

SAVE THE RESULT:
You MUST save the complete enhanced SKILL.md file.

CRITICAL INSTRUCTIONS:
1. First, create a backup: Write the current SKILL.md content to SKILL.md.backup
2. Then, write the enhanced content to: SKILL.md

This is NOT a read-only task - you have permission to modify SKILL.md.
Even if running from within another coding agent session, this modification is ALLOWED and EXPECTED.

VERIFICATION:
After writing, the file SKILL.md should:
- Exist in the current directory
- Be larger than the original (200-1000+ lines)
- Contain all the enhancements from the references above
"""

        return prompt

    def write_status(self, status, message="", progress=0.0, error=None):
        """Write enhancement status to file for monitoring.

        Args:
            status: One of: pending, running, completed, failed
            message: Status message
            progress: Progress percentage (0.0-1.0)
            error: Error message if failed
        """
        status_data = {
            "status": status,
            "message": message,
            "progress": progress,
            "timestamp": datetime.now().isoformat(),
            "skill_dir": str(self.skill_dir),
            "error": error,
        }

        self.status_file.write_text(json.dumps(status_data, indent=2), encoding="utf-8")

    def read_status(self):
        """Read enhancement status from file.

        Returns:
            dict: Status data or None if not found
        """
        if not self.status_file.exists():
            return None

        try:
            return json.loads(self.status_file.read_text(encoding="utf-8"))
        except Exception:
            return None

    def run(self, headless=True, timeout=2700, background=False, daemon=False):
        """Main enhancement workflow with automatic smart summarization for large skills.

        Automatically detects large skills (>30K chars) and applies smart summarization
        to reduce input size for local coding agent CLIs.

        Smart summarization strategy:
        - Keeps first 20% (introduction/overview)
        - Extracts up to 5 best code blocks
        - Keeps up to 10 section headings with first paragraph
        - Reduces to ~30% of original size

        Args:
            headless: If True, run local agent directly without opening terminal (default: True)
            timeout: Maximum time to wait for enhancement in seconds (default: 2700 = 45 minutes)
            background: If True, run in background and return immediately (default: False)
            daemon: If True, run as persistent daemon with monitoring (default: False)

        Returns:
            bool: True if enhancement process started successfully, False otherwise
        """
        # Background mode: Run in background thread, return immediately
        if background:
            return self._run_background(headless, timeout)

        # Daemon mode: Run as persistent process with monitoring
        if daemon:
            return self._run_daemon(timeout)
        print(f"\n{'=' * 60}")
        print(f"LOCAL ENHANCEMENT: {self.skill_dir.name}")
        print(f"Agent: {self.agent_display}")
        print(f"{'=' * 60}\n")

        # Validate
        if not self.skill_dir.exists():
            print(f"❌ Directory not found: {self.skill_dir}")
            return False

        # Read reference files
        print("📖 Reading reference documentation...")
        references = read_reference_files(
            self.skill_dir, max_chars=LOCAL_CONTENT_LIMIT, preview_limit=LOCAL_PREVIEW_LIMIT
        )

        if not references:
            print("❌ No reference files found to analyze")
            return False

        print(f"  ✓ Read {len(references)} reference files")
        total_size = sum(ref["size"] for ref in references.values())
        print(f"  ✓ Total size: {total_size:,} characters\n")

        # Check if we need smart summarization
        use_summarization = total_size > 30000

        if use_summarization:
            print("⚠️  LARGE SKILL DETECTED")
            print(f"  📊 Reference content: {total_size:,} characters")
            if self.agent == "claude":
                print("  💡 CLI agent limit: ~30,000-40,000 characters")
            else:
                print("  💡 Local CLI agents often have input limits; summarizing to be safe")
            print()
            print("  🔧 Applying smart summarization to ensure success...")
            print("     • Keeping introductions and overviews")
            print("     • Extracting best code examples")
            print("     • Preserving key concepts and headings")
            print("     • Target: ~30% of original size")
            print()

        # Create prompt
        print("📝 Creating enhancement prompt...")
        prompt = self.create_enhancement_prompt(use_summarization=use_summarization)

        if not prompt:
            return False

        # Save prompt to temp file
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".txt", delete=False, encoding="utf-8"
        ) as f:
            prompt_file = f.name
            f.write(prompt)

        if use_summarization:
            print(f"  ✓ Prompt created and optimized ({len(prompt):,} characters)")
            if self.agent == "claude":
                print("  ✓ Ready for CLI agent (within safe limits)")
            else:
                print("  ✓ Ready for local CLI (within safe limits)")
            print()
        else:
            print(f"  ✓ Prompt saved ({len(prompt):,} characters)\n")

        # Headless mode: Run local agent directly without opening terminal
        if headless:
            return self._run_headless(prompt_file, timeout)

        # Terminal mode: Launch local agent in new terminal
        print(f"🚀 Launching {self.agent_display} in new terminal...")
        print("   This will:")
        print("   1. Open a new terminal window")
        print("   2. Run the local coding agent with the enhancement task")
        print("   3. The agent will read the docs and enhance SKILL.md")
        print("   4. Terminal will auto-close when done")
        print()

        # Create a shell script to run in the terminal
        command_line = self._format_agent_command(prompt_file, include_permissions_flag=False)
        shell_script = f"""#!/bin/bash
{command_line}
echo ""
echo "✅ Enhancement complete!"
echo "Press any key to close..."
read -n 1
rm {prompt_file}
"""

        # Save shell script
        with tempfile.NamedTemporaryFile(mode="w", suffix=".sh", delete=False) as f:
            script_file = f.name
            f.write(shell_script)

        os.chmod(script_file, 0o755)

        # Launch in new terminal (macOS specific)
        if sys.platform == "darwin":
            # Detect which terminal app to use
            terminal_app, detection_method = detect_terminal_app()

            # Show detection info
            if detection_method == "SKILL_SEEKER_TERMINAL":
                print(f"   Using terminal: {terminal_app} (from SKILL_SEEKER_TERMINAL)")
            elif detection_method == "TERM_PROGRAM":
                print(f"   Using terminal: {terminal_app} (inherited from current terminal)")
            elif detection_method.startswith("unknown TERM_PROGRAM"):
                print(f"⚠️  {detection_method}")
                print("   → Using Terminal.app as fallback")
            else:
                print(f"   Using terminal: {terminal_app} (default)")

            try:
                subprocess.Popen(["open", "-a", terminal_app, script_file])
            except Exception as e:
                print(f"⚠️  Error launching {terminal_app}: {e}")
                print(f"\nManually run: {script_file}")
                return False
        else:
            print("⚠️  Auto-launch only works on macOS")
            print("\nManually run this command in a new terminal:")
            print(f"  {self._format_agent_command(prompt_file, include_permissions_flag=False)}")
            print("\nThen delete the prompt file:")
            print(f"  rm '{prompt_file}'")
            return False

        print(f"✅ New terminal launched with {self.agent_display}!")
        print()
        print("📊 Status:")
        print(f"  - Prompt file: {prompt_file}")
        print(f"  - Skill directory: {self.skill_dir.absolute()}")
        print(f"  - SKILL.md will be saved to: {self.skill_md_path.absolute()}")
        print(
            f"  - Original backed up to: {self.skill_md_path.with_suffix('.md.backup').absolute()}"
        )
        print()
        print("⏳ Wait for the local agent to finish in the other terminal...")
        print("   (Usually takes 30-60 seconds)")
        print()
        print("💡 When done:")
        print(f"  1. Check the enhanced SKILL.md: {self.skill_md_path}")
        print(
            f"  2. If you don't like it, restore: mv {self.skill_md_path.with_suffix('.md.backup')} {self.skill_md_path}"
        )
        print(f"  3. Package: skill-seekers package {self.skill_dir}/")

        return True

    def _run_headless(self, prompt_file, timeout):
        """Run local agent enhancement in headless mode (no terminal window)

        Args:
            prompt_file: Path to prompt file
            timeout: Maximum seconds to wait

        Returns:
            bool: True if enhancement succeeded
        """
        import time

        print(f"✨ Running {self.agent_display} enhancement (headless mode)...")
        print(f"   Timeout: {timeout} seconds ({timeout // 60} minutes)")
        print()

        # Record initial state
        initial_mtime = self.skill_md_path.stat().st_mtime if self.skill_md_path.exists() else 0
        initial_size = self.skill_md_path.stat().st_size if self.skill_md_path.exists() else 0

        # Start timer
        start_time = time.time()

        try:
            # Run local agent command directly (this WAITS for completion)
            print("   ⏳ Please wait...")
            print(f"   Working directory: {self.skill_dir}")
            print()

            result, error = self._run_agent_command(
                prompt_file, timeout, include_permissions_flag=True
            )

            if error:
                print(f"❌ {error}")
                with contextlib.suppress(Exception):
                    os.unlink(prompt_file)
                return False

            elapsed = time.time() - start_time

            # Check if successful
            if result.returncode == 0:
                # Verify SKILL.md was actually updated
                if self.skill_md_path.exists():
                    new_mtime = self.skill_md_path.stat().st_mtime
                    new_size = self.skill_md_path.stat().st_size

                    if new_mtime > initial_mtime and new_size > initial_size:
                        print(f"✅ Enhancement complete! ({elapsed:.1f} seconds)")
                        print(f"   SKILL.md updated: {new_size:,} bytes")
                        print()

                        # Clean up prompt file
                        with contextlib.suppress(Exception):
                            os.unlink(prompt_file)

                        return True
                    else:
                        print("⚠️  Agent finished but SKILL.md was not updated")
                        print(f"   Initial: mtime={initial_mtime}, size={initial_size}")
                        print(f"   Final:   mtime={new_mtime}, size={new_size}")
                        print("   This might indicate an error during enhancement")
                        print()
                        # Show last 20 lines of stdout for debugging
                        if result.stdout:
                            print("   Last output from agent:")
                            lines = result.stdout.strip().split("\n")[-20:]
                            for line in lines:
                                print(f"   | {line}")
                        print()
                        return False
                else:
                    print("❌ SKILL.md not found after enhancement")
                    return False
            else:
                # Exit code 75 = EX_TEMPFAIL (retryable temporary failure from Kimi CLI)
                if result.returncode == 75:
                    print(f"⚠️  {self.agent_display} returned temporary failure (exit code: 75)")
                    print(
                        "   This usually means a transient API issue (timeout, rate limit, or empty response)."
                    )
                    print("   Retrying once in 5 seconds...")
                    print()
                    time.sleep(5)
                    result_retry, error = self._run_agent_command(
                        prompt_file, timeout, include_permissions_flag=True
                    )
                    if error:
                        print(f"❌ {error}")
                        with contextlib.suppress(Exception):
                            os.unlink(prompt_file)
                        return False
                    if result_retry.returncode == 0:
                        elapsed = time.time() - start_time
                        if self.skill_md_path.exists():
                            new_mtime = self.skill_md_path.stat().st_mtime
                            new_size = self.skill_md_path.stat().st_size
                            if new_mtime > initial_mtime and new_size > initial_size:
                                print(f"✅ Enhancement complete on retry! ({elapsed:.1f} seconds)")
                                print(f"   SKILL.md updated: {new_size:,} bytes")
                                print()
                                with contextlib.suppress(Exception):
                                    os.unlink(prompt_file)
                                return True
                    print(f"❌ Retry also failed (exit code: {result_retry.returncode})")
                    if result_retry.stderr:
                        stderr_lines = result_retry.stderr.strip().split("\n")
                        for line in stderr_lines[:10]:
                            print(f"   | {line}")
                    print("   Try again later or use API mode:")
                    print("     export ANTHROPIC_API_KEY=sk-ant-...")
                    print(f"     skill-seekers enhance {self.skill_dir} --target claude")
                    return False

                print(f"❌ {self.agent_display} returned error (exit code: {result.returncode})")
                if result.stderr:
                    stderr_lines = result.stderr.strip().split("\n")
                    for line in stderr_lines[:20]:
                        print(f"   | {line}")
                    if len(stderr_lines) > 20:
                        print(f"   ... ({len(stderr_lines) - 20} more lines)")
                    # Hint for root/permission errors
                    stderr_lower = result.stderr.lower()
                    if result.returncode in (1, 126) and (
                        "root" in stderr_lower or "permission" in stderr_lower
                    ):
                        print()
                        print("   ⚠️  This looks like a root/permission error.")
                        print("   The CLI agent refuses to run as root (security policy).")
                        print("   Use API mode instead:")
                        print("     export ANTHROPIC_API_KEY=sk-ant-...")
                        print(f"     skill-seekers enhance {self.skill_dir} --target claude")
                return False

        except subprocess.TimeoutExpired:
            elapsed = time.time() - start_time
            print(f"\n⚠️  Enhancement timed out after {elapsed:.0f} seconds")
            print(f"   Timeout limit: {timeout} seconds")
            print()
            print("   Possible reasons:")
            print("   - Skill is very large (many references)")
            print("   - Agent is taking longer than usual")
            print("   - Network issues")
            print()
            print("   Try:")
            print("   1. Use terminal mode: --interactive-enhancement")
            print("   2. Reduce reference content")
            print("   3. Try again later")

            # Clean up
            with contextlib.suppress(Exception):
                os.unlink(prompt_file)

            return False

        except FileNotFoundError:
            print(f"❌ '{self._build_agent_command(prompt_file, True)[0][0]}' command not found")
            print()
            print("   Make sure your local coding agent CLI is installed and on PATH.")
            print()
            print("   Try terminal mode instead: --interactive-enhancement")

            return False

        except Exception as e:
            print(f"❌ Unexpected error: {e}")
            return False

    def _run_background(self, headless, timeout):
        """Run enhancement in background thread, return immediately.

        Args:
            headless: Run headless mode
            timeout: Timeout in seconds

        Returns:
            bool: True if background task started successfully
        """
        print(f"\n{'=' * 60}")
        print(f"BACKGROUND ENHANCEMENT: {self.skill_dir.name}")
        print(f"{'=' * 60}\n")

        # Write initial status
        self.write_status("pending", "Starting background enhancement...")

        def background_worker():
            """Worker function for background thread"""
            try:
                self.write_status("running", "Enhancement in progress...", progress=0.1)

                # Read reference files
                references = read_reference_files(
                    self.skill_dir, max_chars=LOCAL_CONTENT_LIMIT, preview_limit=LOCAL_PREVIEW_LIMIT
                )

                if not references:
                    self.write_status("failed", error="No reference files found")
                    return

                total_size = sum(meta["size"] for meta in references.values())
                use_summarization = total_size > 30000

                self.write_status("running", "Creating enhancement prompt...", progress=0.3)

                # Create prompt
                prompt = self.create_enhancement_prompt(use_summarization=use_summarization)
                if not prompt:
                    self.write_status("failed", error="Failed to create prompt")
                    return

                # Save prompt to temp file
                with tempfile.NamedTemporaryFile(
                    mode="w", suffix=".txt", delete=False, encoding="utf-8"
                ) as f:
                    prompt_file = f.name
                    f.write(prompt)

                self.write_status(
                    "running", f"Running {self.agent_display} enhancement...", progress=0.5
                )

                # Run enhancement
                if headless:
                    # Run headless (subprocess.run - blocking in thread)
                    result, error = self._run_agent_command(
                        prompt_file, timeout, include_permissions_flag=True, quiet=True
                    )

                    # Clean up
                    with contextlib.suppress(Exception):
                        os.unlink(prompt_file)

                    if error:
                        self.write_status("failed", error=error)
                    elif result.returncode == 0:
                        self.write_status(
                            "completed", "Enhancement completed successfully!", progress=1.0
                        )
                    else:
                        self.write_status(
                            "failed", error=f"Agent returned error: {result.returncode}"
                        )
                else:
                    # Terminal mode in background doesn't make sense
                    self.write_status("failed", error="Terminal mode not supported in background")

            except subprocess.TimeoutExpired:
                self.write_status("failed", error=f"Enhancement timed out after {timeout} seconds")
            except Exception as e:
                self.write_status("failed", error=str(e))

        # Start background thread
        thread = threading.Thread(target=background_worker, daemon=True)
        thread.start()

        print("✅ Background enhancement started!")
        print()
        print("📊 Monitoring:")
        print(f"  - Status file: {self.status_file}")
        print(f"  - Check status: cat {self.status_file}")
        print(f"  - Or use: skill-seekers enhance-status {self.skill_dir}")
        print()
        print("💡 The enhancement will continue in the background.")
        print("   You can close this terminal - the process will keep running.")
        print()

        return True

    def _run_daemon(self, timeout):
        """Run as persistent daemon process with monitoring.

        Creates a detached background process that continues running even if parent exits.

        Args:
            timeout: Timeout in seconds

        Returns:
            bool: True if daemon started successfully
        """
        print(f"\n{'=' * 60}")
        print(f"DAEMON MODE: {self.skill_dir.name}")
        print(f"{'=' * 60}\n")

        # Write initial status
        self.write_status("pending", "Starting daemon process...")

        print("🔧 Creating daemon process...")

        # Create Python script for daemon
        daemon_script = f'''#!/usr/bin/env python3
import os
import sys
import time
import subprocess
import tempfile
import json
from pathlib import Path
from datetime import datetime

skill_dir = Path("{self.skill_dir}")
status_file = skill_dir / ".enhancement_status.json"
skill_md_path = skill_dir / "SKILL.md"

def write_status(status, message="", progress=0.0, error=None):
    status_data = {{
        "status": status,
        "message": message,
        "progress": progress,
        "timestamp": datetime.now().isoformat(),
        "skill_dir": str(skill_dir),
        "error": error,
        "pid": os.getpid()
    }}
    status_file.write_text(json.dumps(status_data, indent=2), encoding='utf-8')

try:
    write_status("running", "Daemon started, loading references...", progress=0.1)

    # Import enhancement logic
    sys.path.insert(0, "{os.path.dirname(os.path.dirname(os.path.abspath(__file__)))}")
    from skill_seekers.cli.enhance_skill_local import LocalSkillEnhancer

    enhancer = LocalSkillEnhancer(
        "{self.skill_dir}",
        agent="{self.agent}",
        agent_cmd={repr(self.agent_cmd)}
    )

    # Create prompt
    write_status("running", "Creating enhancement prompt...", progress=0.3)
    prompt = enhancer.create_enhancement_prompt(use_summarization=True)

    if not prompt:
        write_status("failed", error="Failed to create prompt")
        sys.exit(1)

    # Save prompt
    with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False, encoding='utf-8') as f:
        prompt_file = f.name
        f.write(prompt)

    write_status("running", "Running local agent...", progress=0.5)

    # Run local agent
    result, error = enhancer._run_agent_command(
        prompt_file,
        timeout={timeout},
        include_permissions_flag=True,
        quiet=True
    )

    # Clean up
    try:
        os.unlink(prompt_file)
    except Exception:
        pass

    if error:
        write_status("failed", error=error)
        sys.exit(1)
    if result.returncode == 0:
        write_status("completed", "Enhancement completed successfully!", progress=1.0)
        sys.exit(0)
    else:
        write_status("failed", error=f"Agent returned error: {{result.returncode}}")
        sys.exit(1)

except subprocess.TimeoutExpired:
    write_status("failed", error=f"Enhancement timed out after {timeout} seconds")
    sys.exit(1)
except Exception as e:
    write_status("failed", error=str(e))
    sys.exit(1)
'''

        # Save daemon script
        daemon_script_path = self.skill_dir / ".enhancement_daemon.py"
        daemon_script_path.write_text(daemon_script, encoding="utf-8")
        daemon_script_path.chmod(0o755)

        # Start daemon process (fully detached)
        try:
            # Use nohup to detach from terminal
            log_file = self.skill_dir / ".enhancement_daemon.log"

            if self.force:
                # Force mode: No output, fully silent
                subprocess.Popen(
                    ["nohup", "python3", str(daemon_script_path)],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL,
                    start_new_session=True,
                )
            else:
                # Normal mode: Log to file
                with open(log_file, "w") as log:
                    subprocess.Popen(
                        ["nohup", "python3", str(daemon_script_path)],
                        stdout=log,
                        stderr=log,
                        start_new_session=True,
                    )

            # Give daemon time to start
            time.sleep(1)

            # Read status to verify it started
            status = self.read_status()

            if status and status.get("status") in ["pending", "running"]:
                print("✅ Daemon process started successfully!")
                print()
                print("📊 Monitoring:")
                print(f"  - Status file: {self.status_file}")
                print(f"  - Log file: {log_file}")
                print(f"  - PID: {status.get('pid', 'unknown')}")
                print()
                print("💡 Commands:")
                print(f"  - Check status: cat {self.status_file}")
                print(f"  - View logs: tail -f {log_file}")
                print(f"  - Or use: skill-seekers enhance-status {self.skill_dir}")
                print()
                print("🔥 The daemon will continue running even if you close this terminal!")
                print()

                return True
            else:
                print("❌ Daemon failed to start")
                return False

        except Exception as e:
            print(f"❌ Failed to start daemon: {e}")
            return False


def _detect_api_target() -> tuple[str, str] | None:
    """
    Auto-detect which API platform to use for enhancement based on env vars.

    Priority: ANTHROPIC_API_KEY > GOOGLE_API_KEY > OPENAI_API_KEY

    Returns:
        (target, api_key) tuple if an API key is found, else None.
    """
    anthropic_key = os.environ.get("ANTHROPIC_API_KEY") or os.environ.get("ANTHROPIC_AUTH_TOKEN")
    if anthropic_key:
        return ("claude", anthropic_key)

    google_key = os.environ.get("GOOGLE_API_KEY")
    if google_key:
        return ("gemini", google_key)

    openai_key = os.environ.get("OPENAI_API_KEY")
    if openai_key:
        return ("openai", openai_key)

    return None


def _run_api_enhance(target: str, api_key: str) -> None:
    """Delegate to enhance_skill.main() for API-mode enhancement."""
    import sys

    from skill_seekers.cli.enhance_skill import main as api_main

    # Find the skill_directory positional arg (first non-flag arg after argv[0])
    skill_dir = None
    dry_run = False
    i = 1
    while i < len(sys.argv):
        arg = sys.argv[i]
        if arg == "--dry-run":
            dry_run = True
        elif arg in ("--mode",):
            i += 1  # skip value
        elif not arg.startswith("-") and skill_dir is None:
            skill_dir = arg
        i += 1

    if not skill_dir:
        print("❌ Error: skill_directory is required")
        sys.exit(1)

    new_argv = [sys.argv[0], skill_dir, "--target", target, "--api-key", api_key]
    if dry_run:
        new_argv.append("--dry-run")
    sys.argv = new_argv
    api_main()


def main():
    import argparse

    parser = argparse.ArgumentParser(
        description="Enhance a skill using AI (auto-detects API or local agent mode)",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Auto-detection (no flags needed):
  If ANTHROPIC_API_KEY is set  → Anthropic API mode
  If GOOGLE_API_KEY is set     → Gemini API mode
  If OPENAI_API_KEY is set     → OpenAI API mode
  Otherwise                    → LOCAL mode (coding agent CLI, free)

Examples:
  # Auto-detect mode based on env vars (recommended)
  skill-seekers enhance output/react/

  # Force LOCAL mode even if API keys are set
  skill-seekers enhance output/react/ --mode LOCAL

  # LOCAL: background mode (runs in background, returns immediately)
  skill-seekers enhance output/react/ --mode LOCAL --background

  # LOCAL: daemon mode (persistent background process, fully detached)
  skill-seekers enhance output/react/ --mode LOCAL --daemon

  # LOCAL: interactive mode (opens terminal window)
  skill-seekers enhance output/react/ --mode LOCAL --interactive-enhancement

  # LOCAL: custom timeout
  skill-seekers enhance output/react/ --mode LOCAL --timeout 1200

LOCAL Mode Comparison:
  - headless:    Runs local agent CLI directly, BLOCKS until done (default)
  - background:  Runs in background thread, returns immediately
  - daemon:      Fully detached process, continues after parent exits
  - terminal:    Opens new terminal window (interactive)

Force Mode (LOCAL only, Default ON):
  By default, all LOCAL modes skip confirmations (auto-yes).
  Use --no-force to enable confirmation prompts.
""",
    )

    parser.add_argument("skill_directory", help="Path to skill directory (e.g., output/react/)")

    parser.add_argument(
        "--mode",
        choices=["LOCAL", "API"],
        help=(
            "Force enhancement mode. LOCAL uses a local coding agent (free). "
            "API uses the platform API (requires API key). "
            "Default: auto-detect from environment variables."
        ),
    )

    parser.add_argument(
        "--agent",
        choices=sorted(list(AGENT_PRESETS.keys()) + ["custom"]),
        help="Local coding agent to use (default: claude or SKILL_SEEKER_AGENT)",
    )

    parser.add_argument(
        "--agent-cmd",
        help=(
            "Override agent command template. Use {prompt_file} placeholder or omit to use stdin. "
            "Can also be set via SKILL_SEEKER_AGENT_CMD."
        ),
    )

    parser.add_argument(
        "--interactive-enhancement",
        action="store_true",
        help="Open terminal window for enhancement (default: headless mode)",
    )

    parser.add_argument(
        "--background",
        action="store_true",
        help="Run in background and return immediately (non-blocking)",
    )

    parser.add_argument(
        "--daemon", action="store_true", help="Run as persistent daemon process (fully detached)"
    )

    parser.add_argument(
        "--no-force",
        action="store_true",
        help="Disable force mode: enable confirmation prompts (default: force mode ON)",
    )

    from skill_seekers.cli.agent_client import get_default_timeout

    parser.add_argument(
        "--timeout",
        type=int,
        default=get_default_timeout(),
        help=(
            "Timeout in seconds for headless mode "
            "(default: 45 minutes, set SKILL_SEEKER_ENHANCE_TIMEOUT to override)"
        ),
    )

    args = parser.parse_args()

    # Auto-detect API mode unless --mode LOCAL is explicitly set
    if getattr(args, "mode", None) != "LOCAL":
        api_target = _detect_api_target()
        if api_target is not None:
            target, api_key = api_target
            _run_api_enhance(target, api_key)
            return

    # Validate mutually exclusive options
    mode_count = sum([args.interactive_enhancement, args.background, args.daemon])
    if mode_count > 1:
        print(
            "❌ Error: --interactive-enhancement, --background, and --daemon are mutually exclusive"
        )
        print("   Choose only one mode")
        sys.exit(1)

    # Run enhancement
    # Force mode is ON by default, use --no-force to disable
    try:
        enhancer = LocalSkillEnhancer(
            args.skill_directory,
            force=not args.no_force,
            agent=args.agent,
            agent_cmd=args.agent_cmd,
        )
    except ValueError as e:
        print(f"❌ Error: {e}")
        sys.exit(1)
    headless = not args.interactive_enhancement  # Invert: default is headless
    success = enhancer.run(
        headless=headless, timeout=args.timeout, background=args.background, daemon=args.daemon
    )

    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()
