# Copyright (C) 2026 GoodData Corporation

"""Target-specific MCP installation handlers."""

from __future__ import annotations

import os
import subprocess
from collections.abc import Sequence
from pathlib import Path

from aida_mcp.server.mcp_install_common import (
    _find_in_path,
    _newest_nvm_claude,
    _npm_prefix_path,
    err,
    log,
)
from aida_mcp.server.mcp_install_config import write_codex_toml_config, write_mcp_json_config


def resolve_claude_bin() -> Path | None:
    env_candidate = os.environ.get("CLAUDE_BIN")
    if env_candidate:
        path = Path(env_candidate).expanduser()
        if path.exists():
            return path

    path_candidate = _find_in_path("claude")
    if path_candidate:
        return path_candidate

    prefix = _npm_prefix_path()
    if prefix:
        candidate = prefix / "bin" / "claude"
        if candidate.exists():
            return candidate

    nvm_dir = Path(os.environ.get("NVM_DIR", Path.home() / ".nvm"))
    candidate = _newest_nvm_claude(nvm_dir)
    if candidate and os.access(candidate, os.X_OK):
        return candidate

    return None


def install_for_cursor(
    *,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    allow_global: bool = False,
) -> None:
    if not allow_global:
        err("Refusing to write global Cursor MCP config without --global.")
        err("Recommended: run `aida-mcp init` in the repo root for repo-local config.")
        raise SystemExit(2)
    dest = Path.home() / ".cursor" / "mcp.json"
    log(f"Installing MCP config for Cursor at {dest}")
    write_mcp_json_config(
        dest=dest,
        command_path=None if http_url else command_path,
        args=args,
        url=http_url,
        workspace_root=workspace_root,
        config_root=config_root,
    )


def install_for_cursor_project(
    *,
    project_root: Path,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    extra_env: dict[str, str] | None = None,
) -> None:
    """Install/merge Cursor project-local MCP config in <project>/.cursor/mcp.json."""
    dest = project_root / ".cursor" / "mcp.json"
    log(f"Installing project-local MCP config for Cursor at {dest}")
    write_mcp_json_config(
        dest=dest,
        command_path=None if http_url else command_path,
        args=args,
        url=http_url,
        workspace_root=workspace_root,
        config_root=config_root,
        extra_env=extra_env,
    )


def install_for_claude_project(
    *,
    project_root: Path,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    extra_env: dict[str, str] | None = None,
) -> None:
    """Install/merge Claude project-local MCP config in <project>/.mcp.json."""
    dest = project_root / ".mcp.json"
    log(f"Installing project-local MCP config for Claude at {dest}")
    write_mcp_json_config(
        dest=dest,
        command_path=None if http_url else command_path,
        args=args,
        url=http_url,
        workspace_root=workspace_root,
        config_root=config_root,
        extra_env=extra_env,
    )


def install_for_codex_project(
    *,
    project_root: Path,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    extra_env: dict[str, str] | None = None,
) -> None:
    """Install/merge Codex project-local config in <project>/.codex/config.toml."""
    dest = project_root / ".codex" / "config.toml"
    log(f"Installing project-local MCP config for Codex at {dest}")
    write_codex_toml_config(
        dest=dest,
        command_path=None if http_url else command_path,
        args=args,
        url=http_url,
        workspace_root=workspace_root,
        config_root=config_root,
        extra_env=extra_env,
    )


def install_for_jetbrains(
    *,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    allow_global: bool = False,
) -> None:
    if not allow_global:
        err("JetBrains AI Chat currently uses only global MCP config.")
        err("Repo-local mcp.json is ignored by JetBrains AI Chat.")
        err("Re-run with: aida-mcp install-mcp --global --target jetbrains")
        err("Target path: ~/.ai/mcp/mcp.json")
        raise SystemExit(2)
    dest = Path.home() / ".ai" / "mcp" / "mcp.json"
    log(f"Installing MCP config for JetBrains AI at {dest}")
    write_mcp_json_config(
        dest=dest,
        command_path=None if http_url else command_path,
        args=args,
        url=http_url,
        workspace_root=workspace_root,
        config_root=config_root,
    )


def install_for_junie(
    *,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    allow_global: bool = False,
) -> None:
    if not allow_global:
        err("Junie currently uses only global MCP config.")
        err("Repo-local mcp.json is ignored by Junie.")
        err("Re-run with: aida-mcp install-mcp --global --target junie")
        err("Target path: ~/.junie/mcp/mcp.json")
        raise SystemExit(2)
    dest = Path.home() / ".junie" / "mcp" / "mcp.json"
    log(f"Installing MCP config for Junie at {dest}")
    write_mcp_json_config(
        dest=dest,
        command_path=None if http_url else command_path,
        args=args,
        url=http_url,
        workspace_root=workspace_root,
        config_root=config_root,
    )


def install_for_codex(
    *,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    allow_global: bool = False,
) -> None:
    if not allow_global:
        err("Refusing to write global Codex MCP config without --global.")
        err("Recommended: run `aida-mcp init` in the repo root for repo-local .codex/config.toml.")
        raise SystemExit(2)
    dest = Path.home() / ".codex" / "config.toml"
    log(f"Installing MCP config for Codex at {dest}")
    write_codex_toml_config(
        dest=dest,
        command_path=None if http_url else command_path,
        args=args,
        url=http_url,
        workspace_root=workspace_root,
        config_root=config_root,
    )


def install_for_claude(
    *,
    command_path: Path,
    args: Sequence[str] = (),
    http_url: str | None = None,
    workspace_root: str | None = None,
    config_root: str | None = None,
    allow_global: bool = False,
) -> None:
    if not allow_global:
        err("Refusing to configure Claude Code MCP without --global.")
        err("Recommended: run `aida-mcp init` in the repo root for repo-local .mcp.json.")
        raise SystemExit(2)
    if http_url:
        err("Experimental HTTP MCP install is not supported via Claude CLI yet.")
        err("Use repo-local/project config targets for HTTP mode, or omit --http for stdio.")
        raise SystemExit(2)
    claude_cli = resolve_claude_bin()
    if not claude_cli:
        err("Claude CLI not found. Install it with `npm i -g @anthropic-ai/claude-code` or set CLAUDE_BIN to its path.")
        err("If you use nvm, ensure nvm is initialized so 'claude' is on PATH.")
        raise SystemExit(1)

    log(f"Configuring Claude Code via CLI ({claude_cli})")

    try:
        get_result = subprocess.run(
            [str(claude_cli), "mcp", "get", "aida"],
            check=False,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )
    except FileNotFoundError:
        err(f"Claude CLI not executable at {claude_cli}")
        raise SystemExit(1)

    if get_result.returncode == 0:
        log("Existing aida entry detected; removing before re-adding")
        remove = subprocess.run(
            [str(claude_cli), "mcp", "remove", "aida"],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.PIPE,
            text=True,
        )
        if remove.returncode != 0:
            err("Failed to remove existing aida entry from Claude CLI")
            err(remove.stderr.strip())
            raise SystemExit(remove.returncode)

    cmd: list[str]
    if workspace_root or config_root:
        cmd = ["/usr/bin/env"]
        if workspace_root:
            cmd.append(f"AIDA_WORKSPACE_ROOT={workspace_root}")
        if config_root:
            cmd.append(f"AIDA_CONFIG_ROOT={config_root}")
        cmd.append(str(command_path))
        cmd.extend(args)
    else:
        cmd = [str(command_path), *args]

    result = subprocess.run(
        [str(claude_cli), "mcp", "add", "--transport", "stdio", "aida", "--", *cmd],
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        err("Claude CLI failed to register aida MCP server")
        err(result.stderr.strip())
        raise SystemExit(result.returncode)
    log("Claude CLI now trusts aida MCP server")
