"""CloudSense Customer Compass MCP server.

Run with: python -m cloudsense_customer_compass.server
Or via CLI: cloudsense-customer-compass
"""

import asyncio
import logging
import sys
import time

from anyio import BrokenResourceError, ClosedResourceError
from mcp.server import Server
from mcp.server.stdio import stdio_server
import mcp.types as types

from . import __version__
from .instructions import SERVER_INSTRUCTIONS
from .utils.telemetry import init_session, log_tool_call, end_session
from .tools import (
    connect_lma,
    find_customer,
    get_customer_licenses,
    get_portfolio_data,
    save_report,
)

logger = logging.getLogger(__name__)

server = Server("cloudsense-customer-compass")

TOOLS = {
    "connect_lma": connect_lma,
    "find_customer": find_customer,
    "get_customer_licenses": get_customer_licenses,
    "get_portfolio_data": get_portfolio_data,
    "save_report": save_report,
}

@server.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name=mod.TOOL_DEFINITION["name"],
            description=mod.TOOL_DEFINITION["description"],
            inputSchema=mod.TOOL_DEFINITION["inputSchema"],
        )
        for mod in TOOLS.values()
    ]


@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
    start = time.monotonic()
    error_info = None

    tool_module = TOOLS.get(name)
    if tool_module is None:
        result = f"STATUS: ERROR\n\nUnknown tool: {name}"
        log_tool_call(name, arguments, result, 0, f"Unknown tool: {name}")
        return [types.TextContent(type="text", text=result)]
    try:
        result = await tool_module.run(arguments)
    except Exception as e:
        logger.exception("Tool '%s' failed with unhandled exception", name)
        error_type = type(e).__name__
        error_detail = str(e)
        error_info = f"{error_type}: {error_detail}"
        result = (
            f"STATUS: UNEXPECTED_ERROR\n\n"
            f"Tool `{name}` failed with {error_type}: {error_detail}\n\n"
            f"Diagnose the error and tell the user what went wrong in "
            f"plain language. Common causes:\n"
            f"- 'SfCliError' or 'TimeoutExpired': Salesforce CLI issue — "
            f"check if the org is still authorized, or if sf CLI is "
            f"installed and on PATH.\n"
            f"- 'FileNotFoundError': A required file or command is missing.\n"
            f"- 'JSONDecodeError': The CLI returned unexpected output.\n"
            f"- 'SafetyViolationError': The command was blocked by the "
            f"read-only safety policy.\n\n"
            f"Ask the user if they'd like to try again or need help "
            f"resolving the issue."
        )

    duration_ms = (time.monotonic() - start) * 1000
    log_tool_call(name, arguments, result, duration_ms, error_info)
    return [types.TextContent(type="text", text=result)]


def _is_disconnect(exc: BaseException) -> bool:
    if isinstance(exc, (BrokenResourceError, ClosedResourceError)):
        return True
    if isinstance(exc, BaseExceptionGroup):
        return all(_is_disconnect(e) for e in exc.exceptions)
    return False


async def _run_server():
    logger.info("CloudSense Customer Compass v%s starting...", __version__)
    init_session("customer-compass", __version__)
    try:
        async with stdio_server() as (read_stream, write_stream):
            init_options = server.create_initialization_options()
            init_options.instructions = SERVER_INSTRUCTIONS
            await server.run(read_stream, write_stream, init_options)
    except BaseExceptionGroup as eg:
        if _is_disconnect(eg):
            logger.info("Client disconnected — shutting down.")
        else:
            raise
    except (BrokenResourceError, ClosedResourceError):
        logger.info("Client disconnected — shutting down.")
    finally:
        end_session()


def main():
    logging.basicConfig(level=logging.INFO)
    try:
        asyncio.run(_run_server())
    except KeyboardInterrupt:
        pass
    except (BrokenPipeError, EOFError):
        logger.info("Pipe closed — exiting.")
    sys.exit(0)


if __name__ == "__main__":
    main()
