"""CLI entrypoints for oh-my-linear."""

from __future__ import annotations

import argparse
import json
import shlex
import sys
from pathlib import Path
from typing import Any, Sequence

from .server import main as serve_main

DEFAULT_SERVER_NAME = "oh-my-linear"
DEFAULT_STDIO_COMMAND = "uvx"
DEFAULT_STDIO_ARGS = ["oh-my-linear"]


def _load_mcp_config(config_path: Path) -> dict[str, Any]:
    if not config_path.exists():
        return {"mcpServers": {}}

    try:
        parsed = json.loads(config_path.read_text(encoding="utf-8"))
    except json.JSONDecodeError as exc:
        raise RuntimeError(f"invalid JSON in {config_path}: {exc}") from exc

    if not isinstance(parsed, dict):
        raise RuntimeError(f"expected top-level object in {config_path}")

    servers = parsed.get("mcpServers")
    if servers is None:
        parsed["mcpServers"] = {}
        return parsed

    if not isinstance(servers, dict):
        raise RuntimeError(f"expected 'mcpServers' to be an object in {config_path}")
    return parsed


def _save_mcp_config(config_path: Path, config: dict[str, Any]) -> None:
    config_path.write_text(
        json.dumps(config, ensure_ascii=True, indent=2) + "\n",
        encoding="utf-8",
    )


def command_install(
    project: str,
    name: str,
    stdio_command: str,
    stdio_args: list[str] | None,
    client: str,
) -> int:
    project_dir = Path(project).expanduser().resolve()
    if not project_dir.exists():
        print(f"Project directory does not exist: {project_dir}", file=sys.stderr)
        return 2
    if not project_dir.is_dir():
        print(f"Project path is not a directory: {project_dir}", file=sys.stderr)
        return 2

    config_path = project_dir / ".mcp.json"
    try:
        config = _load_mcp_config(config_path)
    except RuntimeError as exc:
        print(str(exc), file=sys.stderr)
        return 2

    args = list(stdio_args) if stdio_args else list(DEFAULT_STDIO_ARGS)

    existing_entry = config["mcpServers"].get(name)
    next_entry: dict[str, Any] = dict(existing_entry) if isinstance(existing_entry, dict) else {}
    next_entry.update(
        {
            "type": "stdio",
            "command": stdio_command,
            "args": args,
        }
    )

    config["mcpServers"][name] = next_entry
    _save_mcp_config(config_path, config)

    command_preview = " ".join([shlex.quote(stdio_command), *[shlex.quote(item) for item in args]])
    print(f"Updated MCP server '{name}' in {config_path}")
    print("")
    print("Use one of these commands:")
    if client in {"claude", "both"}:
        print(f"- Claude Code: claude mcp add {name} -- {command_preview}")
    if client in {"codex", "both"}:
        print(f"- Codex: codex mcp add {name} -- {command_preview}")
    return 0


def _build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="oh-my-linear",
        description="Unified Linear MCP server (local-fast reads + official fallback/writes).",
    )
    subparsers = parser.add_subparsers(dest="command")

    subparsers.add_parser("serve", help="Run MCP server (default when no args).")

    install = subparsers.add_parser(
        "install",
        help="Add or update this server entry in a project's .mcp.json.",
    )
    install.add_argument(
        "--project",
        default=".",
        help="Project directory that contains .mcp.json (default: current directory).",
    )
    install.add_argument(
        "--name",
        default=DEFAULT_SERVER_NAME,
        help=f"MCP server name in .mcp.json (default: {DEFAULT_SERVER_NAME}).",
    )
    install.add_argument(
        "--command",
        dest="stdio_command",
        default=DEFAULT_STDIO_COMMAND,
        help=f"Stdio command for the server entry (default: {DEFAULT_STDIO_COMMAND}).",
    )
    install.add_argument(
        "--arg",
        action="append",
        dest="stdio_args",
        help="Add one stdio arg. Repeat this flag for multiple args.",
    )
    install.add_argument(
        "--client",
        choices=("claude", "codex", "both"),
        default="both",
        help="Which client setup command to print (default: both).",
    )

    return parser


def main(argv: Sequence[str] | None = None) -> None:
    args = list(argv) if argv is not None else sys.argv[1:]
    if not args:
        serve_main()
        return

    parser = _build_parser()
    parsed = parser.parse_args(args)

    if parsed.command in (None, "serve"):
        serve_main()
        return

    if parsed.command == "install":
        code = command_install(
            project=parsed.project,
            name=parsed.name,
            stdio_command=parsed.stdio_command,
            stdio_args=parsed.stdio_args,
            client=parsed.client,
        )
        if code != 0:
            raise SystemExit(code)
        return

    parser.error(f"unknown command: {parsed.command}")
