#!/usr/bin/env python3
"""
CloudSense DX MCP Server.

Provides MCP tools and prompts for CloudSense DX operations
(orchestration template management, etc.).

Run directly:     python -m cloudsense_dx_mcp.server
Via entry point:  cloudsense-dx-mcp
"""

import asyncio
import json
import sys
from typing import Any, Dict, List

from mcp.server import Server
from mcp.server.models import InitializationOptions
from mcp.server.stdio import stdio_server
from mcp.types import (
    GetPromptResult,
    Prompt,
    PromptArgument,
    PromptMessage,
    PromptsCapability,
    ServerCapabilities,
    TextContent,
    Tool,
    ToolsCapability,
)

from .tools import list_templates, fetch_templates, run_apex

# ---------------------------------------------------------------------------
# Server instructions (sent to MCP clients on initialization)
# ---------------------------------------------------------------------------

SERVER_INSTRUCTIONS = """\
You are connected to the CloudSense DX MCP server. Use the tools provided by \
this server for orchestration template operations and CloudSense-specific tasks.

TOOL ROUTING (follow these rules strictly):

1. list_orchestration_templates -- Use when the user wants to SEE or BROWSE templates.
   Trigger words: "show", "list", "what templates", "search", "find", "which templates", \
   "how many templates".
   This tool returns template names and IDs only. It does NOT download template content.

2. fetch_orchestration_templates -- Use when the user wants to GET or SAVE templates.
   Trigger words: "get", "fetch", "download", "export", "pull", "save", "retrieve".
   This tool downloads the full template JSON and saves files to disk.
   When the user says "get 10 templates" or "get all templates", use THIS tool, not list.

3. run_apex -- Use ONLY when the user explicitly asks to run Apex code, execute Apex \
   statements, or when the request cannot be fulfilled by the two tools above.
   Do NOT use run_apex for orchestration template operations -- always prefer \
   list_orchestration_templates or fetch_orchestration_templates instead.

ORG RESOLUTION (IMPORTANT -- do NOT ask the user which org to use):
- If the user mentions an org (e.g. "from itxdevpro", "on p2dev"), pass it as org_alias.
- If the user gives a partial hint (e.g. "devpro"), pass it as-is -- the tool \
  will fuzzy-match it against authenticated orgs.
- If the user does NOT mention any org, simply OMIT the org_alias parameter. \
  The tool will automatically resolve the org from the session history or the \
  workspace default.
- After every tool call, tell the user which org was used (from the response's \
  "org" and "org_source" fields).

DO NOT use Salesforce DX MCP or other tools for orchestration template operations \
or CloudSense-specific operations -- always use this server's tools.\
"""

# ---------------------------------------------------------------------------
# MCP Server
# ---------------------------------------------------------------------------

app = Server("cloudsense-dx")

# ---------------------------------------------------------------------------
# Tools
# ---------------------------------------------------------------------------

_TOOLS = {
    list_templates.TOOL_NAME: list_templates,
    fetch_templates.TOOL_NAME: fetch_templates,
    run_apex.TOOL_NAME: run_apex,
}


@app.list_tools()
async def handle_list_tools() -> List[Tool]:
    return [Tool(**t.TOOL_DEFINITION) for t in _TOOLS.values()]


@app.call_tool()
async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextContent]:
    tool_module = _TOOLS.get(name)
    if not tool_module:
        return [TextContent(type="text", text=json.dumps({"error": f"Unknown tool: {name}"}))]

    try:
        result_text = await tool_module.execute(arguments or {})
        return [TextContent(type="text", text=result_text)]
    except Exception as e:
        return [TextContent(
            type="text",
            text=json.dumps({"success": False, "error": str(e)}, indent=2),
        )]

# ---------------------------------------------------------------------------
# Prompts
# ---------------------------------------------------------------------------

@app.list_prompts()
async def handle_list_prompts() -> List[Prompt]:
    return [
        Prompt(
            name="fetch-orchestration",
            description=(
                "Guided workflow to fetch orchestration process templates from a "
                "Salesforce org. Walks through org selection, template discovery, "
                "user confirmation, and parallel fetching."
            ),
            arguments=[
                PromptArgument(
                    name="org_alias",
                    description=(
                        "Salesforce org alias (e.g. 'itxdevpro'). "
                        "Leave blank to use the default target-org from sf CLI."
                    ),
                    required=False,
                ),
                PromptArgument(
                    name="template_names",
                    description=(
                        "Comma-separated template names to fetch, or 'all' to fetch "
                        "every template. Leave blank to be guided through discovery."
                    ),
                    required=False,
                ),
            ],
        ),
    ]


@app.get_prompt()
async def handle_get_prompt(name: str, arguments: Dict[str, str] | None) -> GetPromptResult:
    if name != "fetch-orchestration":
        raise ValueError(f"Unknown prompt: {name}")

    args = arguments or {}
    org_alias = args.get("org_alias", "").strip()
    template_names = args.get("template_names", "").strip()

    workflow_text = _build_fetch_orchestration_prompt(org_alias, template_names)

    return GetPromptResult(
        description="Guided workflow for fetching orchestration process templates",
        messages=[
            PromptMessage(
                role="user",
                content=TextContent(type="text", text=workflow_text),
            )
        ],
    )


def _build_fetch_orchestration_prompt(org_alias: str, template_names: str) -> str:
    lines = [
        "You are helping the user fetch CloudSense orchestration process templates.",
        "Follow these steps carefully:",
        "",
    ]

    # Step 1: Org
    if org_alias:
        lines.append(f"1. TARGET ORG: Use org alias '{org_alias}'.")
    else:
        lines.append(
            "1. TARGET ORG: No org was specified. "
            "Omit the org_alias parameter so the tool uses the sf CLI default target-org. "
            "Mention to the user which org will be used."
        )

    # Step 2: Template discovery
    if template_names.lower() == "all":
        lines.append(
            "2. TEMPLATES: The user wants ALL templates. "
            "Call fetch_orchestration_templates without template_names to fetch everything."
        )
    elif template_names:
        names_list = [n.strip() for n in template_names.split(",") if n.strip()]
        lines.append(
            f"2. TEMPLATES: The user specified these templates: {names_list}. "
            "First, call list_orchestration_templates with a search_term for each name "
            "to verify they exist. If any don't match exactly, show the user the closest "
            "matches and ask for confirmation before proceeding."
        )
    else:
        lines.append(
            "2. TEMPLATES: No specific templates were requested. "
            "Ask the user: do they want ALL templates, or specific ones? "
            "If specific, ask for names (they can be partial -- you'll search). "
            "Use list_orchestration_templates with a search_term to find matches, "
            "present the results, and confirm with the user before fetching."
        )

    # Step 3: Fetch
    lines.extend([
        "",
        "3. FETCH: Once templates are confirmed, call fetch_orchestration_templates "
        "with the confirmed template_names (and org_alias if specified). "
        "Use default max_workers (5) unless the user requests otherwise.",
        "",
        "4. RESULTS: After fetching, summarize the results clearly:",
        "   - How many templates succeeded vs failed",
        "   - The output directory where files were saved",
        "   - List any failures with their error messages",
        "   - If templates failed because they don't exist, suggest using "
        "list_orchestration_templates to find the correct names",
    ])

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

async def _run_server():
    async with stdio_server() as (read_stream, write_stream):
        await app.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="cloudsense-dx",
                server_version="0.2.2",
                capabilities=ServerCapabilities(
                    tools=ToolsCapability(),
                    prompts=PromptsCapability(),
                ),
                instructions=SERVER_INSTRUCTIONS,
            ),
        )


def main():
    """CLI entry point for the CloudSense DX MCP server."""
    asyncio.run(_run_server())


if __name__ == "__main__":
    main()
