from __future__ import annotations

"""
Copyright (C) 2025 Luciano Guerche

This file is part of rabbitmq-mcp-server.

rabbitmq-mcp-server is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

rabbitmq-mcp-server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with rabbitmq-mcp-server. If not, see <https://www.gnu.org/licenses/>.
"""

"""MCP tool handler for HTTP-based RabbitMQ Management API operations."""

import json
import uuid
from typing import Any

import structlog
from pydantic import ValidationError

from rabbitmq_mcp_connection.executor import ExecutionResult, OperationExecutor
from rabbitmq_mcp_connection.schemas.mcp import MCPError, MCPToolResult

logger = structlog.get_logger(__name__)


async def handle_call_id_http(
    operation_id: str,
    parameters: dict[str, Any] | None = None,
    executor: OperationExecutor | None = None,
) -> MCPToolResult:
    """Handle call-id tool request for HTTP Management API operations.

    Executes RabbitMQ Management API operations via HTTP with validated parameters.
    Implements AC #1, #2, #5 requirements for call-id tool.

    Args:
        operation_id: Operation identifier from registry (e.g., "queues.list")
        parameters: Operation-specific parameters (default: {})
        executor: OperationExecutor instance (must be provided)

    Returns:
        MCPToolResult with execution result or error

    Example:
        >>> result = await handle_call_id_http(
        ...     "queues.list",
        ...     {"vhost": "/"},
        ...     executor=executor
        ... )
        >>> if result.success:
        ...     print(result.result["result"])
    """
    # Generate correlation ID for request tracing
    correlation_id = str(uuid.uuid4())

    # Validate operation_id is non-empty (AC #2)
    if not operation_id or not operation_id.strip():
        logger.warning(
            "call_id_http.invalid_parameter",
            operation_id=operation_id,
            error="empty_operation_id",
            correlation_id=correlation_id,
        )
        return MCPToolResult(
            success=False,
            error=MCPError(
                code="INVALID_PARAMETER",
                message="Parameter 'operation_id' is required and must be non-empty",
            ),
        )

    # Validate executor is provided
    if executor is None:
        logger.error(
            "call_id_http.no_executor",
            operation_id=operation_id,
            correlation_id=correlation_id,
        )
        return MCPToolResult(
            success=False,
            error=MCPError(
                code="INTERNAL_ERROR",
                message="Executor not initialized",
            ),
        )

    # Default parameters to empty dict
    parameters = parameters or {}

    try:
        # Log operation execution start
        logger.info(
            "call_id_http.execute_start",
            operation_id=operation_id,
            parameter_count=len(parameters),
            correlation_id=correlation_id,
        )

        # Execute operation via OperationExecutor
        result: ExecutionResult = await executor.execute(operation_id, parameters)

        # Log operation completion
        logger.info(
            "call_id_http.execute_complete",
            operation_id=operation_id,
            status=result.status,
            response_time_ms=result.metadata.get("response_time_ms"),
            correlation_id=correlation_id,
        )

        # Check if execution succeeded
        if result.status == "success":
            # Format response with pretty-printed JSON (AC #5)
            formatted_result = json.dumps(
                {
                    "status": result.status,
                    "result": result.result,
                    "correlation_id": result.correlation_id,
                    "metadata": result.metadata,
                },
                indent=2,
                ensure_ascii=False,
            )

            return MCPToolResult(
                success=True,
                result={
                    "raw": result.result,
                    "formatted": formatted_result,
                    "metadata": result.metadata,
                },
            )
        else:
            # Execution failed, return error from result
            error_data = result.result
            return MCPToolResult(
                success=False,
                error=MCPError(
                    code=error_data.get("error_code", "UNKNOWN_ERROR"),
                    message=error_data.get("message", "Operation failed"),
                    details=error_data.get("context", {}),
                ),
            )

    except KeyError as exc:
        # Operation not found in registry
        logger.warning(
            "call_id_http.operation_not_found",
            operation_id=operation_id,
            correlation_id=correlation_id,
        )
        return MCPToolResult(
            success=False,
            error=MCPError(
                code="OPERATION_NOT_FOUND",
                message=str(exc),
            ),
        )

    except ValidationError as exc:
        # Parameter validation failed (AC #2)
        logger.warning(
            "call_id_http.validation_error",
            operation_id=operation_id,
            errors=exc.errors(),
            correlation_id=correlation_id,
        )

        # Extract first error for user-friendly message
        errors = exc.errors()
        first_error = dict(errors[0]) if errors else {}
        loc = first_error.get("loc", ["unknown"])
        field = str(loc[0]) if isinstance(loc, list | tuple) and loc else "unknown"
        msg = first_error.get("msg", "Validation failed")

        return MCPToolResult(
            success=False,
            error=MCPError(
                code="INVALID_PARAMETER",
                message=f"Parameter '{field}' validation failed: {msg}",
                details={"errors": errors},
            ),
        )

    except Exception as exc:
        # Unexpected error
        logger.exception(
            "call_id_http.unhandled_exception",
            operation_id=operation_id,
            correlation_id=correlation_id,
        )
        return MCPToolResult(
            success=False,
            error=MCPError(
                code="INTERNAL_ERROR",
                message="Unexpected error during operation execution",
                details={"error": str(exc), "type": type(exc).__name__},
            ),
        )


__all__ = ["handle_call_id_http"]
