"""MCP server that wraps the Atlassian CLI (acli) into generic tools."""

import asyncio
import json
import shlex
import shutil
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("acli-mcp-server")


def _acli_available() -> bool:
    return shutil.which("acli") is not None


async def _run_acli(command: str, timeout: int = 60) -> dict:
    """Execute an acli command and return structured output."""
    if not _acli_available():
        return {"error": "acli is not installed or not in PATH"}

    if not command.startswith("acli "):
        command = f"acli {command}"

    # Split into args and validate the binary is 'acli'
    try:
        args = shlex.split(command)
    except ValueError as e:
        return {"error": f"Invalid command syntax: {e}"}

    if not args or args[0] != "acli":
        return {"error": "Command must start with 'acli'"}

    # Block shell operators
    dangerous = {";", "&&", "||", "|", "`", "$(", "${", ">", "<", ">>"}
    for arg in args:
        for d in dangerous:
            if d in arg:
                return {"error": f"Blocked: shell operator '{d}' not allowed"}

    try:
        proc = await asyncio.create_subprocess_exec(
            *args,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, stderr = await asyncio.wait_for(
            proc.communicate(), timeout=timeout
        )
    except asyncio.TimeoutError:
        return {"error": f"Command timed out after {timeout}s: {command}"}

    result: dict = {"command": command, "exit_code": proc.returncode}
    out = stdout.decode().strip() if stdout else ""
    err = stderr.decode().strip() if stderr else ""

    if proc.returncode != 0:
        result["error"] = err or "Command failed"
        if out:
            result["output"] = out
        return result

    # Try to parse as JSON for structured output
    try:
        result["output"] = json.loads(out)
    except (json.JSONDecodeError, ValueError):
        result["output"] = out

    if err:
        result["stderr"] = err

    return result


@mcp.tool()
async def call_acli(cli_command: str, timeout: int = 60) -> str:
    """Execute an Atlassian CLI (acli) command.

    The command must start with 'acli' and follow acli syntax.
    Examples:
      - acli jira workitem list --site site.atlassian.net --project PROJ
      - acli jira workitem create --site site.atlassian.net --project PROJ --type Task --summary "Title"
      - acli jira workitem view --site site.atlassian.net --workitem PROJ-123
      - acli jira project list --site site.atlassian.net
      - acli jira sprint list --site site.atlassian.net --board 1
      - acli confluence page list --site site.atlassian.net --space SPACE
      - acli confluence page view --site site.atlassian.net --page 123456

    Args:
        cli_command: The full acli command to execute.
        timeout: Max seconds to wait for the command (default 60).
    """
    result = await _run_acli(cli_command, timeout)
    return json.dumps(result, indent=2, default=str)


@mcp.tool()
async def suggest_acli_commands(query: str) -> str:
    """Suggest acli commands based on a natural language description.

    Useful when you're unsure about the exact acli command syntax.

    Args:
        query: Natural language description of what you want to do.
    """
    suggestions = {
        "workitem": [
            "acli jira workitem list --site SITE --project PROJ",
            "acli jira workitem create --site SITE --project PROJ --type Task --summary 'Title'",
            "acli jira workitem view --site SITE --workitem PROJ-123",
            "acli jira workitem edit --site SITE --workitem PROJ-123 --summary 'New title'",
            "acli jira workitem transition --site SITE --workitem PROJ-123 --transition 'Done'",
        ],
        "project": [
            "acli jira project list --site SITE",
            "acli jira project view --site SITE --project PROJ",
        ],
        "board": [
            "acli jira board list --site SITE",
            "acli jira board view --site SITE --board 1",
        ],
        "sprint": [
            "acli jira sprint list --site SITE --board 1",
            "acli jira sprint view --site SITE --sprint 1",
        ],
        "page": [
            "acli confluence page list --site SITE --space SPACE",
            "acli confluence page view --site SITE --page 123456",
            "acli confluence page create --site SITE --space SPACE --title 'Title' --body 'Content'",
        ],
        "space": [
            "acli confluence space list --site SITE",
            "acli confluence space view --site SITE --space SPACE",
        ],
        "blog": [
            "acli confluence blog list --site SITE --space SPACE",
        ],
        "auth": [
            "acli jira auth login --web",
            "acli jira auth status",
            "acli confluence auth login --web",
        ],
    }

    q = query.lower()
    matched = []
    for category, cmds in suggestions.items():
        if category in q or any(kw in q for kw in category):
            matched.extend(cmds)

    if not matched:
        matched = [f"# {cat}\n" + "\n".join(cmds) for cat, cmds in suggestions.items()]

    return json.dumps({"query": query, "suggestions": matched}, indent=2)


def main():
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()
