"""
Claude Client Module - Claude Code CLI integration.

Contains:
- spawn_claude_code: Spawn Claude CLI subprocess
- consolidate_with_claude: Process clusters via LLM
"""

import asyncio
import os
import shutil
import subprocess
import sys
from typing import Any, Dict, List

from ..cli_utils import get_subprocess_env, get_session_dir, build_claude_cli_args

from .models import Cluster
from .prompting import build_consolidation_prompt, parse_consolidation_response


async def spawn_claude_code(prompt: str, project: str = "_global", timeout: int = 180) -> str:
    """
    Spawn Claude Code CLI as subprocess and get response.

    Args:
        prompt: The prompt to send to Claude
        project: Project name for session logs directory (default: "_global")
        timeout: Timeout in seconds
    """

    # Find claude executable
    claude_exe = shutil.which("claude")
    if not claude_exe:
        # Try common Windows locations
        possible_paths = [
            os.path.expanduser("~/.claude/local/claude.exe"),
            os.path.expanduser("~/AppData/Local/Programs/claude/claude.exe"),
            "C:/Program Files/Claude/claude.exe",
        ]
        for path in possible_paths:
            if os.path.exists(path):
                claude_exe = path
                break

    if not claude_exe:
        raise RuntimeError(
            "Claude Code CLI not found in PATH. "
            "Please ensure Claude Code is installed and accessible."
        )

    # Get dedicated session directory for this script
    session_logs_dir = get_session_dir(project, "memory_consolidator")

    # Spawn Claude Code with --print flag
    # --dangerously-skip-permissions: Skip permission prompts (headless)
    # --model haiku: Use Haiku for faster, cheaper consolidation
    # creationflags: Prevent console window on Windows
    kwargs = {
        "stdout": asyncio.subprocess.PIPE,
        "stderr": asyncio.subprocess.PIPE,
        "env": get_subprocess_env(),
        "cwd": str(session_logs_dir),  # Isolate sessions from user's project
    }

    # Add Windows-specific flag to hide console window
    if sys.platform == 'win32':
        kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW

    cli_args = build_claude_cli_args(prompt, model="haiku")
    process = await asyncio.create_subprocess_exec(
        claude_exe,
        *cli_args,
        **kwargs
    )

    try:
        stdout, stderr = await asyncio.wait_for(
            process.communicate(),
            timeout=timeout
        )
    except asyncio.TimeoutError:
        process.kill()
        await process.wait()
        raise RuntimeError(f"Claude Code CLI timed out after {timeout} seconds")

    if process.returncode != 0:
        error_msg = stderr.decode('utf-8', errors='replace') if stderr else "Unknown error"
        raise RuntimeError(f"Claude Code CLI failed: {error_msg}")

    return stdout.decode('utf-8', errors='replace')


async def consolidate_with_claude(clusters: List[Cluster]) -> List[Dict[str, Any]]:
    """
    Send clusters to Claude for consolidation decisions.

    Returns list of consolidation decisions.
    """
    if not clusters:
        return []

    print(f"[Consolidate] Processing {len(clusters)} clusters via LLM...")
    prompt = build_consolidation_prompt(clusters)
    print(f"[Consolidate] Prompt built ({len(prompt)} chars), calling Claude CLI...")

    # Extract project from first cluster's first memory for session logs directory
    project = "_global"
    if clusters and clusters[0].memories:
        project = clusters[0].memories[0].get("project", "_global")

    try:
        response = await spawn_claude_code(prompt, project=project, timeout=180)
        print(f"[Consolidate] Claude CLI returned {len(response)} chars")
        consolidations = parse_consolidation_response(response)
        print(f"[Consolidate] Parsed {len(consolidations)} consolidation decisions")
        return consolidations
    except Exception as e:
        import traceback
        print(f"[Consolidate] LLM call failed: {e}")
        print(f"[Consolidate] Traceback: {traceback.format_exc()}")
        # Return keep_all as safe default for all clusters
        return [
            {
                "cluster_id": c.id,
                "decision": "keep_all",
                "reasoning": f"LLM processing failed, defaulting to keep_all: {str(e)[:50]}",
                "error": True
            }
            for c in clusters
        ]
