"""MCP installation logic."""

import json
import subprocess
from pathlib import Path
from typing import Any, Dict, List, Optional

from .config_parser import VibePackageConfig


class MCPInstaller:
    """Handles MCP installation operations."""

    def __init__(
        self,
        base_dir: str,
        target_agents: List[str],
        debug_mode: bool = False,
        tracker: Optional[Any] = None,
        config: Optional[VibePackageConfig] = None,
    ):
        """
        Initialize MCPInstaller.

        Args:
            base_dir: Base directory for operations
            target_agents: List of target agents
            debug_mode: Enable debug logging
            tracker: PackageTracker instance to track loaded packages
            config: VibePackageConfig instance for agent-specific configurations
        """
        self.base_dir = Path(base_dir).resolve()
        self.target_agents = target_agents
        self.debug_mode = debug_mode
        self.tracker = tracker
        self.config = config

        self._debug_log(
            f"MCPInstaller initialized with base_dir: {self.base_dir}, target_agents: {target_agents}"
        )

    def _debug_log(self, message: str) -> None:
        """Print debug message if debug mode is enabled."""
        if self.debug_mode:
            print(f"[DEBUG] [MCPInstaller] {message}")

    def _get_agent_cli_command(self, agent: str) -> str:
        """Get the CLI command for an agent."""
        if self.config:
            return self.config.get_agent_cli_command(agent)
        return agent

    def _get_mcp_commands(self, agent: str) -> Dict[str, str]:
        """Get MCP subcommands for an agent."""
        if self.config:
            return self.config.get_agent_mcp_commands(agent)
        return {"add": "add-json", "remove": "remove"}

    def _remove_mcp(self, agent: str, mcp_name: str) -> bool:
        """
        Remove an MCP if it exists.

        Args:
            agent: Agent name (e.g., 'claude', 'iflow')
            mcp_name: Name of the MCP

        Returns:
            True if MCP was removed or didn't exist, False if removal failed
        """
        cli_command = self._get_agent_cli_command(agent)
        mcp_commands = self._get_mcp_commands(agent)
        remove_cmd = mcp_commands.get("remove", "remove")

        cmd_string = f'{cli_command} mcp {remove_cmd} "{mcp_name}"'
        self._debug_log(f"Attempting to remove MCP '{mcp_name}' for agent '{agent}': {cmd_string}")

        try:
            result = subprocess.run(
                cmd_string,
                shell=True,
                capture_output=True,
                text=True,
                cwd=self.base_dir,
                timeout=30,
            )
            self._debug_log(f"Remove command returned code: {result.returncode}")

            if result.returncode == 0:
                self._debug_log(f"Successfully removed MCP '{mcp_name}' for agent '{agent}'")
                return True
            else:
                # MCP might not exist, that's okay
                stderr_lower = result.stderr.lower() if result.stderr else ""
                if "not found" in stderr_lower or "does not exist" in stderr_lower:
                    self._debug_log(
                        f"MCP '{mcp_name}' does not exist for agent '{agent}', skipping removal"
                    )
                    return True
                else:
                    self._debug_log(
                        f"Failed to remove MCP '{mcp_name}' for agent '{agent}': {result.stderr}"
                    )
                    return False
        except subprocess.TimeoutExpired:
            self._debug_log(f"Timeout removing MCP '{mcp_name}' for agent '{agent}'")
            return True
        except (OSError, subprocess.SubprocessError) as e:
            self._debug_log(f"Error removing MCP '{mcp_name}' for agent '{agent}': {e}")
            # Don't fail the whole process if removal fails
            return True

    def install_mcp(self, mcp_name: str, mcp_config: Dict[str, Any]) -> None:
        """
        Install an MCP using the provided command and args.

        Args:
            mcp_name: Name of the MCP
            mcp_config: MCP configuration dictionary

        Raises:
            ValueError: If required fields are missing or invalid
            RuntimeError: If installation fails
        """
        self._debug_log(f"Starting installation of MCP: {mcp_name}")

        command = mcp_config.get("command")
        args = mcp_config.get("args")

        if not command:
            self._debug_log("No command found in configuration")
            raise ValueError(f"MCP '{mcp_name}' missing required field: 'command'")

        if not args:
            self._debug_log("No args found in configuration")
            raise ValueError(f"MCP '{mcp_name}' missing required field: 'args'")

        if not isinstance(args, list):
            self._debug_log(f"Args must be a list, got {type(args)}")
            raise ValueError(f"MCP '{mcp_name}' 'args' field must be a list")

        self._debug_log(f"Command: {command}")
        self._debug_log(f"Args: {args}")

        # Build JSON config string
        config_json = json.dumps({"command": command, "args": args})

        print(f"Installing MCP '{mcp_name}' for agents: {', '.join(self.target_agents)}")

        for agent in self.target_agents:
            try:
                # Remove existing MCP first
                self._debug_log(f"Checking for existing MCP '{mcp_name}' for agent '{agent}'")
                self._remove_mcp(agent, mcp_name)

                # Get agent-specific command configuration
                cli_command = self._get_agent_cli_command(agent)
                mcp_commands = self._get_mcp_commands(agent)
                add_cmd = mcp_commands.get("add", "add-json")
                format_type = mcp_commands.get("format", "json")

                # Build command based on agent's command format
                if format_type == "expanded":
                    # Format: {cli_command} mcp add {mcp_name} -- {command} {args...}
                    args_str = " ".join(args)
                    cmd_string = f"{cli_command} mcp {add_cmd} {mcp_name} -- {command} {args_str}"
                elif add_cmd == "add":
                    # Format: {cli_command} mcp add '{mcp_name}' '{config_json}'
                    cmd_string = f"{cli_command} mcp add '{mcp_name}' '{config_json}'"
                else:
                    # Format: {cli_command} mcp add-json "{mcp_name}" "{escaped_json}"
                    escaped_json = config_json.replace('"', '\\"')
                    cmd_string = f'{cli_command} mcp {add_cmd} "{mcp_name}" "{escaped_json}"'

                self._debug_log(f"Executing command for agent '{agent}': {cmd_string}")

                result = subprocess.run(
                    cmd_string,
                    shell=True,
                    check=True,
                    capture_output=True,
                    text=True,
                    cwd=self.base_dir,
                    timeout=60,
                )

                self._debug_log(
                    f"Command executed successfully for agent '{agent}', return code: {result.returncode}"
                )

                if result.stdout:
                    self._debug_log(f"Stdout: {result.stdout[:200]}...")
                    print(result.stdout)

                print(f"[OK] Successfully installed MCP '{mcp_name}' for agent '{agent}'")
                self._debug_log(f"MCP '{mcp_name}' installed successfully for agent '{agent}'")

                # Mark MCP as loaded if tracker is available
                if self.tracker:
                    self.tracker.mark_mcp_loaded(mcp_name)

            except subprocess.TimeoutExpired as e:
                self._debug_log(f"Installation timed out for agent '{agent}'")
                raise RuntimeError(
                    f"Failed to install MCP '{mcp_name}' for agent '{agent}': Command timed out"
                ) from e
            except subprocess.CalledProcessError as e:
                self._debug_log(
                    f"Installation failed for agent '{agent}' with return code: {e.returncode}"
                )
                error_msg = f"Failed to install MCP '{mcp_name}' for agent '{agent}'"
                if e.stderr:
                    self._debug_log(f"Stderr: {e.stderr}")
                    error_msg += f"\nError: {e.stderr}"
                raise RuntimeError(error_msg) from e
