"""
FiftyOne MCP Server.

Main entrypoint for the FiftyOne Model Context Protocol server.

| Copyright 2017-2025, Voxel51, Inc.
| `voxel51.com <https://voxel51.com/>`_
|
"""

import asyncio
import json
import logging
from pathlib import Path

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import TextContent

from .tools.datasets import get_dataset_tools
from .tools.operators import get_operator_tools
from .tools.plugins import get_plugin_tools
from .tools.session import get_session_tools
from .tools import datasets, operators, plugins, session
from .tools.utils import format_response


logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)


def load_config():
    """Loads configuration from settings.json.

    Returns:
        a config dict
    """
    config_path = Path(__file__).parent / "config" / "settings.json"
    try:
        with open(config_path, "r") as f:
            return json.load(f)
    except Exception as e:
        logger.warning(f"Could not load config from {config_path}: {e}")
        return {}


async def main():
    """Main server function."""
    config = load_config()
    server_config = config.get("server", {})
    server_name = server_config.get("name", "fiftyone-mcp")

    logger.info(f"Starting {server_name} server...")

    server = Server(server_name)

    all_tools = (
        get_dataset_tools()
        + get_operator_tools()
        + get_plugin_tools()
        + get_session_tools()
    )

    @server.list_tools()
    async def list_tools_handler():
        return all_tools

    @server.call_tool()
    async def call_tool_handler(name, arguments):
        if name in ["list_datasets", "load_dataset", "dataset_summary"]:
            return await datasets.handle_tool_call(name, arguments)
        elif name in [
            "set_context",
            "get_context",
            "list_operators",
            "get_operator_schema",
            "execute_operator",
        ]:
            return await operators.handle_tool_call(name, arguments)
        elif name in [
            "list_plugins",
            "get_plugin_info",
            "download_plugin",
            "enable_plugin",
            "disable_plugin",
        ]:
            return await plugins.handle_plugin_tool(name, arguments)
        elif name in [
            "launch_app",
            "close_app",
            "get_session_info",
            "set_view",
            "clear_view",
        ]:
            return await session.handle_session_tool(name, arguments)
        else:
            result = format_response(
                None, success=False, error=f"Unknown tool: {name}"
            )
            return [
                TextContent(type="text", text=json.dumps(result, indent=2))
            ]

    logger.info(f"{server_name} server initialized successfully")

    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream, write_stream, server.create_initialization_options()
        )


def run():
    """Entry point for the server."""
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("Server stopped by user")
    except Exception as e:
        logger.error(f"Server error: {e}", exc_info=True)
        raise


if __name__ == "__main__":
    run()
