#!/usr/bin/env python3
"""
MCP Server for BPM Documentation

Provides two tools:
1. get_bpm_guide_index - Get index of documentation sections
2. get_bpm_guide_content - Get content of a specific section by ID
"""

import asyncio
import os
import sys
import tempfile
from pathlib import Path
from typing import Any, Sequence, Optional

try:
    from importlib import resources
except ImportError:
    # Python < 3.7 fallback
    try:
        import importlib_resources as resources
    except ImportError:
        resources = None

try:
    from mcp.server import Server
    from mcp.server.stdio import stdio_server
    from mcp.types import (
        Tool,
        TextContent,
        ImageContent,
        EmbeddedResource,
    )
    USE_MCP_SDK = True
except ImportError:
    # Fallback: try fastmcp
    try:
        from fastmcp import FastMCP
        USE_MCP_SDK = False
        USE_FASTMCP = True
    except ImportError:
        print("Error: No MCP library found. Install with: pip install mcp", file=sys.stderr)
        sys.exit(1)

from redflagbpm.mcp.md_retriever import MDRetriever


# Initialize MDRetriever
# You can configure the database path here
retriever = MDRetriever(db_path="md_docs.db")

# Path to the BPM Developer Guide
# Uses the bundled resource file from the package
def get_bpm_guide_path() -> Optional[Path]:
    """Get the path to the BPM Developer Guide from package resources."""
    # Check environment variable first (allows override)
    env_path = os.environ.get("BPM_GUIDE_PATH")
    if env_path:
        path = Path(env_path)
        if path.exists():
            return path
        else:
            print(f"Warning: BPM_GUIDE_PATH set to {env_path} but file does not exist", file=sys.stderr)
    
    # Use the bundled resource from the package
    if resources is None:
        print("Warning: importlib.resources not available", file=sys.stderr)
        return None
    
    try:
        # Access the resource file from the package
        resource_package = "redflagbpm.resources"
        resource_name = "BPM_Developer_Guide.md"
        
        # For Python 3.9+, use files() API
        if sys.version_info >= (3, 9):
            resource_path = resources.files(resource_package)
            guide_file = resource_path / resource_name
            # Try to read the file content
            try:
                guide_content = guide_file.read_text(encoding='utf-8')
            except (FileNotFoundError, AttributeError):
                # Fallback to read_text API
                guide_content = resources.read_text(resource_package, resource_name, encoding='utf-8')
        else:
            # For Python 3.7-3.8, use legacy API
            guide_content = resources.read_text(resource_package, resource_name, encoding='utf-8')
        
        # Extract to temporary file for MDRetriever to use
        temp_file = tempfile.NamedTemporaryFile(
            mode='w', 
            suffix='.md', 
            delete=False,
            encoding='utf-8'
        )
        temp_path = Path(temp_file.name)
        temp_file.write(guide_content)
        temp_file.close()
        return temp_path
    except (ImportError, FileNotFoundError, ModuleNotFoundError, AttributeError) as e:
        print(f"Warning: Could not load BPM_Developer_Guide.md from package resources: {e}", file=sys.stderr)
        return None

BPM_GUIDE_PATH = get_bpm_guide_path()

# Agent ID - can be configured via environment variable or parameter
AGENT_ID = os.environ.get("BPM_AGENT_ID", "BPM/DEVELOPER_GUIDE")
MD_RESOURCES = ["BPM_Developer_Guide.md"]


if USE_MCP_SDK:
    # Initialize the MCP server using official SDK
    server = Server("bpm-docs-server")

    @server.list_tools()
    async def list_tools() -> list[Tool]:
        """List available tools."""
        return [
            Tool(
                name="get_bpm_guide_index",
                description=(
                    "Obtiene el índice de todas las secciones de documentación disponibles. "
                    "Retorna una lista con los IDs, títulos y keywords de cada sección. "
                    "Usa esta herramienta para explorar qué secciones están disponibles."
                ),
                inputSchema={
                    "type": "object",
                    "properties": {},
                    "required": []
                }
            ),
            Tool(
                name="get_bpm_guide_content",
                description=(
                    "Recupera el contenido completo de una sección específica de la documentación. "
                    "Requiere el ID de la sección (formato: 'index#section-id'). "
                    "Usa esta herramienta después de obtener el índice para leer el contenido detallado."
                ),
                inputSchema={
                    "type": "object",
                    "properties": {
                        "id": {
                            "type": "string",
                            "description": "Identificador único de la sección (formato: 'index#section-id')"
                        }
                    },
                    "required": ["id"]
                }
            )
        ]

    @server.call_tool()
    async def call_tool(name: str, arguments: dict[str, Any] | None) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
        """Handle tool calls."""
        if arguments is None:
            arguments = {}
        
        if name == "get_bpm_guide_index":
            # Ensure document is processed
            if BPM_GUIDE_PATH and BPM_GUIDE_PATH.exists():
                index = f"{AGENT_ID}/{MD_RESOURCES[0]}"
                retriever.process_document(index, str(BPM_GUIDE_PATH))
            elif BPM_GUIDE_PATH is None:
                return [
                    TextContent(
                        type="text",
                        text="Error: No se pudo cargar BPM_Developer_Guide.md desde los recursos del paquete. "
                             "El archivo debería estar incluido en redflagbpm.resources. "
                             "Como alternativa, configura la variable de entorno BPM_GUIDE_PATH con la ruta al archivo."
                    )
                ]
            
            # Get index info
            result = retriever.get_index_info(AGENT_ID, MD_RESOURCES)
            
            return [
                TextContent(
                    type="text",
                    text=result
                )
            ]
        
        elif name == "get_bpm_guide_content":
            doc_id = arguments.get("id")
            if not doc_id:
                return [
                    TextContent(
                        type="text",
                        text="Error: Se requiere el parámetro 'id'"
                    )
                ]
            
            doc = retriever.get_document_by_id(doc_id)
            if doc:
                content = doc.get("content", "No hay información disponible.")
                return [
                    TextContent(
                        type="text",
                        text=content
                    )
                ]
            else:
                return [
                    TextContent(
                        type="text",
                        text="No hay información disponible para el ID proporcionado. "
                             "Por favor, ejecuta la herramienta get_bpm_guide_index para recuperar el índice de contenidos y verificar los IDs disponibles."
                    )
                ]
        
        else:
            return [
                TextContent(
                    type="text",
                    text=f"Error: Herramienta desconocida: {name}"
                )
            ]

    async def main():
        """Main entry point for the MCP server."""
        async with stdio_server() as (read_stream, write_stream):
            await server.run(
                read_stream,
                write_stream,
                server.create_initialization_options()
            )

elif USE_FASTMCP:
    # Alternative implementation using FastMCP
    mcp = FastMCP("BPM Documentation Server")

    @mcp.tool()
    def get_bpm_guide_index() -> str:
        """
        Obtiene el índice de todas las secciones de documentación disponibles.
        Retorna una lista con los IDs, títulos y keywords de cada sección.
        Usa esta herramienta para explorar qué secciones están disponibles.
        IMPORTANTE: SIEMPRE usa esta herramienta para obtener el índice de las secciones de la documentación ANTES de usar la herramienta get_bpm_guide_content.
        """
        # Ensure document is processed
        if BPM_GUIDE_PATH and BPM_GUIDE_PATH.exists():
            index = f"{AGENT_ID}/{MD_RESOURCES[0]}"
            retriever.process_document(index, str(BPM_GUIDE_PATH))
        elif BPM_GUIDE_PATH is None:
            return "Error: No se pudo cargar BPM_Developer_Guide.md desde los recursos del paquete. " \
                   "El archivo debería estar incluido en redflagbpm.resources. " \
                   "Como alternativa, configura la variable de entorno BPM_GUIDE_PATH con la ruta al archivo."
        
        # Get index info
        return retriever.get_index_info(AGENT_ID, MD_RESOURCES)

    @mcp.tool()
    def get_bpm_guide_content(id: str) -> str:
        """
        Recupera el contenido completo de una sección específica de la documentación.
        IMPORTANTE: SIEMPRE usa la herramienta get_bpm_guide_index para obtener el índice de las secciones de la documentación ANTES de usar esta herramienta.
        Args:
            id: Identificador único de la sección (formato: 'index#section-id')
        """
        doc = retriever.get_document_by_id(id)
        if doc:
            return doc.get("content", "No hay información disponible.")
        else:
            return "No hay información disponible para el ID proporcionado. " \
                   "Por favor, ejecuta la herramienta get_bpm_guide_index para recuperar el índice de contenidos y verificar los IDs disponibles."

    def main():
        """Main entry point for the FastMCP server."""
        mcp.run()

def run():
    """Entry point for uvx and script execution."""
    if USE_MCP_SDK:
        asyncio.run(main())
    else:
        main()


if __name__ == "__main__":
    run()

