"""GDB data view tools — list, get, create, update, 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_data_view_list(
    database_id: int,
    instance: str | None = None,
) -> dict[str, Any]:
    """List data views for a database.

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

    Returns:
        dict with count, views.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            data = await client.get(f"/api/v1/database/{database_id}/data/views")
            views = data if isinstance(data, list) else []
            return {"count": len(views), "views": views}
    except GDBClientError as e:
        raise translate_error(e, resource_type="data_view") from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def gdb_data_view_list_all(
    instance: str | None = None,
) -> dict[str, Any]:
    """List all data views across all databases.

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

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


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def gdb_data_view_get(
    code: str,
    version: str,
    view_id: int,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get a data view by database code, version and view ID.

    Args:
        code: Database code.
        version: Database version.
        view_id: View ID.
        instance: Instance name (default: auto-select).

    Returns:
        dict with view details.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            result: dict[str, Any] = await client.get(
                f"/data-view/{code.lower()}/{version}/{view_id}"
            )
            return result
    except GDBClientError as e:
        raise translate_error(e, resource_type="data_view", resource_id=view_id) from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def gdb_data_view_get_detail(
    code: str,
    version: str,
    catalog_id: int,
    view_version: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get detailed data view with field info.

    Args:
        code: Database code.
        version: Database version.
        catalog_id: Catalog ID.
        view_version: View version string.
        instance: Instance name (default: auto-select).

    Returns:
        dict with detailed view including fields.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            result: dict[str, Any] = await client.get(
                f"/data-view/{code.lower()}/{version}/{catalog_id}/{view_version}/detail"
            )
            return result
    except GDBClientError as e:
        raise translate_error(
            e, resource_type="data_view", resource_id=catalog_id
        ) from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False))
async def gdb_data_view_create(
    database_id: int,
    name: str,
    description: str | None = None,
    group_id: int | None = None,
    is_draft: bool | None = None,
    filters: dict[str, Any] | list[Any] | None = None,
    group_by: dict[str, Any] | list[Any] | None = None,
    aggregates: dict[str, Any] | list[Any] | None = None,
    anonymous: bool | None = None,
    is_flatten: bool | None = None,
    is_log: bool | None = None,
    show_history_logs: bool | None = None,
    order_fields: dict[str, Any] | list[Any] | None = None,
    join_type: str | None = None,
    instance: str | None = None,
) -> dict[str, Any]:
    """Create a data view. Audited write operation.

    Args:
        database_id: Database ID.
        name: View name (required).
        description: View description.
        group_id: Group ID to assign the view to.
        is_draft: Whether the view is a draft.
        filters: Filter configuration (JSON).
        group_by: Group-by configuration (JSON).
        aggregates: Aggregate configuration (JSON).
        anonymous: Whether the view is public.
        is_flatten: Flatten nested records.
        is_log: Enable logging.
        show_history_logs: Show history logs.
        order_fields: Field ordering configuration (JSON).
        join_type: Join type string.
        instance: Instance name (default: auto-select).

    Returns:
        dict with created view data.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            body: dict[str, Any] = {"name": name}
            _add_optional(body, "description", description)
            _add_optional(body, "group_id", group_id)
            _add_optional(body, "is_draft", is_draft)
            _add_optional(body, "filters", filters)
            _add_optional(body, "group_by", group_by)
            _add_optional(body, "aggregates", aggregates)
            _add_optional(body, "anonymous", anonymous)
            _add_optional(body, "is_flatten", is_flatten)
            _add_optional(body, "is_log", is_log)
            _add_optional(body, "show_history_logs", show_history_logs)
            _add_optional(body, "order_fields", order_fields)
            _add_optional(body, "join_type", join_type)
            result: dict[str, Any] = await client.post(
                f"/api/v1/database/{database_id}/data/view/modify",
                data=body,
            )
            return result
    except GDBClientError as e:
        raise translate_error(e, resource_type="data_view") from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False))
async def gdb_data_view_update(
    database_id: int,
    view_id: int,
    name: str | None = None,
    description: str | None = None,
    group_id: int | None = None,
    is_draft: bool | None = None,
    filters: dict[str, Any] | list[Any] | None = None,
    group_by: dict[str, Any] | list[Any] | None = None,
    aggregates: dict[str, Any] | list[Any] | None = None,
    anonymous: bool | None = None,
    is_flatten: bool | None = None,
    is_log: bool | None = None,
    show_history_logs: bool | None = None,
    order_fields: dict[str, Any] | list[Any] | None = None,
    join_type: str | None = None,
    instance: str | None = None,
) -> dict[str, Any]:
    """Update a data view. Audited write operation.

    Args:
        database_id: Database ID.
        view_id: View ID to update.
        name: View name.
        description: View description.
        group_id: Group ID to assign the view to.
        is_draft: Whether the view is a draft.
        filters: Filter configuration (JSON).
        group_by: Group-by configuration (JSON).
        aggregates: Aggregate configuration (JSON).
        anonymous: Whether the view is public.
        is_flatten: Flatten nested records.
        is_log: Enable logging.
        show_history_logs: Show history logs.
        order_fields: Field ordering configuration (JSON).
        join_type: Join type string.
        instance: Instance name (default: auto-select).

    Returns:
        dict with updated view data.
    """
    try:
        async with GDBClient.for_instance(instance) as client:
            body: dict[str, Any] = {"id": view_id}
            _add_optional(body, "name", name)
            _add_optional(body, "description", description)
            _add_optional(body, "group_id", group_id)
            _add_optional(body, "is_draft", is_draft)
            _add_optional(body, "filters", filters)
            _add_optional(body, "group_by", group_by)
            _add_optional(body, "aggregates", aggregates)
            _add_optional(body, "anonymous", anonymous)
            _add_optional(body, "is_flatten", is_flatten)
            _add_optional(body, "is_log", is_log)
            _add_optional(body, "show_history_logs", show_history_logs)
            _add_optional(body, "order_fields", order_fields)
            _add_optional(body, "join_type", join_type)
            result: dict[str, Any] = await client.post(
                f"/api/v1/database/{database_id}/data/view/modify",
                data=body,
            )
            return result
    except GDBClientError as e:
        raise translate_error(e, resource_type="data_view", resource_id=view_id) from e


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False))
async def gdb_data_view_delete(
    data_view_uuid: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Delete a data view by UUID. Audited write operation.

    Args:
        data_view_uuid: UUID of the data view to delete.
        instance: Instance name (default: auto-select).

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