"""Mappings from MCP tools to FastAPI endpoints.

This module defines how MCP tool arguments are transformed into HTTP
requests to the FastAPI backend, and how responses are transformed back.
"""

from __future__ import annotations

from collections.abc import Callable
from typing import Any

__all__ = [
    "TOOL_MAPPINGS",
    "get_mapping",
    "transform_request",
    "transform_response",
]


class EndpointMapping:
    """Configuration for mapping an MCP tool to a FastAPI endpoint."""

    def __init__(
        self,
        method: str,
        path: str,
        request_transformer: Callable[[dict[str, Any]], dict[str, Any]] | None = None,
        response_transformer: Callable[[Any], Any] | None = None,
    ) -> None:
        """Initialize endpoint mapping.

        Args:
            method: HTTP method (GET, POST, etc.)
            path: API endpoint path
            request_transformer: Optional function to transform MCP args to
                HTTP params
            response_transformer: Optional function to transform HTTP response
                to MCP format
        """
        self.method = method
        self.path = path
        self.request_transformer = request_transformer or (lambda x: x)
        self.response_transformer = response_transformer or (lambda x: x)


def _build_cell_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform build_cell MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'params' key for query parameters
    """
    return {
        "params": {
            "name": args["name"],
            "with_metadata": args.get("with_metadata", True),
            "register": args.get("register", True),
        }
    }


def _build_cells_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform build_cells MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'params' key for query parameters and 'json_data' for body
    """
    return {
        "params": {
            "with_metadata": args.get("with_metadata", True),
            "register": args.get("register", True),
        },
        "json_data": args["names"],
    }


def _list_cells_response(response: Any) -> dict[str, Any]:
    """Transform list_cells response to MCP format.

    Args:
        response: FastAPI response (list of cell names)

    Returns:
        Formatted response with cell names
    """
    if isinstance(response, list):
        return {"cells": response, "count": len(response)}
    return response


def _get_cell_info_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform get_cell_info MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'params' key for query parameters
    """
    return {"params": {"name": args["name"]}}


def _download_gds_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform download_gds MCP args to FastAPI path.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with modified 'path' for the endpoint
    """
    path = args["path"]
    # The path template in FastAPI is /api/download/{path:path}.gds
    # We need to construct the full path
    return {"path": f"/api/download/{path}.gds"}


def _download_gds_response(response: Any) -> dict[str, Any]:
    """Transform download_gds response to MCP format.

    Args:
        response: FastAPI response (file path or error)

    Returns:
        Formatted response with file path
    """
    # If response is a string (text), it's likely the file content or path
    if isinstance(response, str):
        return {"status": "success", "message": response}
    return response


def _check_drc_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform check_drc MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'json_data' key for request body
    """
    json_data: dict[str, Any] = {"path": args["path"]}

    # Add optional parameters if provided
    if "pdk" in args and args["pdk"]:
        json_data["pdk"] = args["pdk"]
    if "process" in args and args["process"]:
        json_data["process"] = args["process"]
    if "timeout" in args and args["timeout"]:
        json_data["timeout"] = args["timeout"]
    if "host" in args and args["host"]:
        json_data["host"] = args["host"]

    return {"json_data": json_data}


def _check_connectivity_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform check_connectivity MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'json_data' key for request body
    """
    return {"json_data": {"path": args["path"]}}


def _check_lvs_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform check_lvs MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'json_data' key for request body
    """
    return {
        "json_data": {
            "cell": args["cell"],
            "netpath": args["netpath"],
            "cellargs": args.get("cellargs", ""),
        }
    }


def _simulate_component_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform simulate_component MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'params' key for query parameters
    """
    return {"params": {"name": args["name"]}}


def _get_port_center_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform get_port_center MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'params' key for query parameters
    """
    return {
        "params": {
            "netlist": args["netlist"],
            "instance": args["instance"],
            "port": args["port"],
        }
    }


def _generate_bbox_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform generate_bbox MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'json_data' key for request body
    """
    json_data: dict[str, Any] = {"path": args["path"]}

    # Add optional parameters if provided
    if "outpath" in args and args["outpath"]:
        json_data["outpath"] = args["outpath"]
    if "layers_to_keep" in args and args["layers_to_keep"]:
        json_data["layers_to_keep"] = args["layers_to_keep"]
    if "bbox_layer" in args and args["bbox_layer"]:
        json_data["bbox_layer"] = args["bbox_layer"]
    if "ignore_ports" in args:
        json_data["ignore_ports"] = args["ignore_ports"]

    return {"json_data": json_data}


def _freeze_cell_request(args: dict[str, Any]) -> dict[str, Any]:
    """Transform freeze_cell MCP args to FastAPI params.

    Args:
        args: MCP tool arguments

    Returns:
        Dict with 'path' and 'json_data' for the request
    """
    cell_name = args["cell_name"]
    kwargs = args.get("kwargs", {})

    # The freeze endpoint expects a JSON string in the body.
    # httpx with json= will JSON-encode the dict and send it as the body,
    # which FastAPI's Body() will read as a string.
    return {
        "path": f"/freeze/{cell_name}",
        "json_data": kwargs,  # httpx will JSON-encode this to a string
    }


# Tool name -> Endpoint mapping
TOOL_MAPPINGS: dict[str, EndpointMapping] = {
    # Phase 1: Core Building Tools
    "build_cell": EndpointMapping(
        method="GET",
        path="/api/build-cell",
        request_transformer=_build_cell_request,
    ),
    "build_cells": EndpointMapping(
        method="POST",
        path="/api/build-cells",
        request_transformer=_build_cells_request,
    ),
    "list_cells": EndpointMapping(
        method="GET",
        path="/api/cells",
        response_transformer=_list_cells_response,
    ),
    "get_cell_info": EndpointMapping(
        method="GET",
        path="/api/cell-info",
        request_transformer=_get_cell_info_request,
    ),
    "download_gds": EndpointMapping(
        method="GET",
        path="/api/download/{path}.gds",
        request_transformer=_download_gds_request,
        response_transformer=_download_gds_response,
    ),
    # Phase 2: Verification Tools
    "check_drc": EndpointMapping(
        method="POST",
        path="/api/check-drc",
        request_transformer=_check_drc_request,
    ),
    "check_connectivity": EndpointMapping(
        method="POST",
        path="/api/check-connectivity",
        request_transformer=_check_connectivity_request,
    ),
    "check_lvs": EndpointMapping(
        method="POST",
        path="/api/check-lvs",
        request_transformer=_check_lvs_request,
    ),
    # Phase 4: Simulation & Advanced Tools
    "simulate_component": EndpointMapping(
        method="GET",
        path="/api/simulate",
        request_transformer=_simulate_component_request,
    ),
    "get_port_center": EndpointMapping(
        method="GET",
        path="/api/port-center",
        request_transformer=_get_port_center_request,
    ),
    "generate_bbox": EndpointMapping(
        method="POST",
        path="/api/bbox",
        request_transformer=_generate_bbox_request,
    ),
    "freeze_cell": EndpointMapping(
        method="POST",
        path="/freeze/{cell_name}",
        request_transformer=_freeze_cell_request,
    ),
    "get_pdk_info": EndpointMapping(
        method="GET",
        path="/info",
    ),
}


def get_mapping(tool_name: str) -> EndpointMapping | None:
    """Get the endpoint mapping for a tool.

    Args:
        tool_name: Name of the MCP tool

    Returns:
        EndpointMapping or None if not found
    """
    return TOOL_MAPPINGS.get(tool_name)


def transform_request(
    tool_name: str,
    args: dict[str, Any],
) -> dict[str, Any]:
    """Transform MCP tool arguments to HTTP request parameters.

    Args:
        tool_name: Name of the MCP tool
        args: Tool arguments from MCP

    Returns:
        Dict containing HTTP request parameters (params, json_data, path, etc.)
    """
    mapping = get_mapping(tool_name)
    if mapping is None:
        return {}

    return mapping.request_transformer(args)


def transform_response(tool_name: str, response: Any) -> Any:
    """Transform HTTP response to MCP format.

    Args:
        tool_name: Name of the MCP tool
        response: HTTP response from FastAPI

    Returns:
        Transformed response for MCP
    """
    mapping = get_mapping(tool_name)
    if mapping is None:
        return response

    return mapping.response_transformer(response)
