"""GDB service tools — list, get, create, update, set_visible, delete."""

from __future__ import annotations

from typing import Any

from mcp.types import ToolAnnotations

from mcp_eregistrations_gdb.gdb_client import GDBClient, GDBClientError, translate_error
from mcp_eregistrations_gdb.server import mcp
from mcp_eregistrations_gdb.tools import _add_optional


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def gdb_service_list(instance: str | None = None) -> dict[str, Any]:
    """List all GDB services.

    Args:
        instance: Instance name (default: auto-select).

    Returns:
        dict with count, services.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            data = await client.get("/services")
            if isinstance(data, list):
                services = data
            else:
                services = data.get("results", [])
            return {"count": len(services), "services": services}
    except GDBClientError as e:
        raise translate_error(e, resource_type="service") from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def gdb_service_get(
    service_id: int,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get a GDB service by ID.

    Args:
        service_id: Integer ID of the service.
        instance: Instance name (default: auto-select).

    Returns:
        dict with service details.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            result: dict[str, Any] = await client.get(f"/api/v1/services/{service_id}")
            return result
    except GDBClientError as e:
        raise translate_error(e, resource_type="service", resource_id=service_id) from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False))
async def gdb_service_create(
    name: str,
    path: str,
    catalog_id: int,
    template: str,
    parameters: dict[str, Any] | None = None,
    method: str | None = None,
    response_schema: dict[str, Any] | None = None,
    instance: str | None = None,
) -> dict[str, Any]:
    """Create a GDB service. Audited write operation.

    Args:
        name: Service name.
        path: Service URL path.
        catalog_id: ID of the parent catalog.
        template: Template identifier.
        parameters: Optional JSON parameters (default: None).
        method: HTTP method override (default: None).
        response_schema: Response JSON schema (default: None).
        instance: Instance name (default: auto-select).

    Returns:
        dict with created service details.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            body: dict[str, Any] = {
                "name": name,
                "path": path,
                "catalog_id": catalog_id,
                "template": template,
            }
            _add_optional(body, "parameters", parameters)
            _add_optional(body, "method", method)
            _add_optional(body, "responseSchema", response_schema)
            result: dict[str, Any] = await client.post(
                "/api/v1/service/modify", data=body
            )
            return result
    except GDBClientError as e:
        raise translate_error(e, resource_type="service") from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False))
async def gdb_service_update(
    service_id: int,
    name: str | None = None,
    path: str | None = None,
    catalog_id: int | None = None,
    template: str | None = None,
    parameters: dict[str, Any] | None = None,
    method: str | None = None,
    response_schema: dict[str, Any] | None = None,
    instance: str | None = None,
) -> dict[str, Any]:
    """Update a GDB service. Audited write operation.

    Args:
        service_id: Integer ID of the service to update.
        name: New service name (default: None).
        path: New service URL path (default: None).
        catalog_id: New parent catalog ID (default: None).
        template: New template identifier (default: None).
        parameters: New JSON parameters (default: None).
        method: New HTTP method override (default: None).
        response_schema: New response JSON schema (default: None).
        instance: Instance name (default: auto-select).

    Returns:
        dict with updated service details.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            body: dict[str, Any] = {"id": service_id}
            _add_optional(body, "name", name)
            _add_optional(body, "path", path)
            _add_optional(body, "catalog_id", catalog_id)
            _add_optional(body, "template", template)
            _add_optional(body, "parameters", parameters)
            _add_optional(body, "method", method)
            _add_optional(body, "responseSchema", response_schema)
            result: dict[str, Any] = await client.post(
                "/api/v1/service/modify", data=body
            )
            return result
    except GDBClientError as e:
        raise translate_error(e, resource_type="service", resource_id=service_id) from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False))
async def gdb_service_set_visible(
    service_id: int,
    visible: bool,
    instance: str | None = None,
) -> dict[str, Any]:
    """Set GDB service visibility. Audited write operation.

    Args:
        service_id: Integer ID of the service.
        visible: Whether the service should be visible.
        instance: Instance name (default: auto-select).

    Returns:
        dict with service_id, visible.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            await client.put(
                f"/api/v1/service/{service_id}/visible",
                data={"value": visible},
            )
            return {"service_id": service_id, "visible": visible}
    except GDBClientError as e:
        raise translate_error(e, resource_type="service", resource_id=service_id) from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False))
async def gdb_service_delete(
    service_id: int,
    instance: str | None = None,
) -> dict[str, Any]:
    """Delete a GDB service. Audited write operation.

    Args:
        service_id: Integer ID of the service to delete.
        instance: Instance name (default: auto-select).

    Returns:
        dict with deleted (bool), service_id.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            await client.delete(f"/api/v1/service/{service_id}")
            return {"deleted": True, "service_id": service_id}
    except GDBClientError as e:
        raise translate_error(e, resource_type="service", resource_id=service_id) from e
