"""MCP tools for DS system operations.

Provides health check, authentication, and business entity listing.
"""

from __future__ import annotations

from typing import Any

from fastmcp.exceptions import ToolError
from mcp.types import ToolAnnotations

from mcp_eregistrations_common.auth import (
    AuthenticationError,
    keycloak_password_grant,
    store_shared_tokens,
)
from mcp_eregistrations_common.config import get_instance_config
from mcp_eregistrations_ds.ds_client import (
    DSClient,
    DSClientError,
    store_ds_token,
    translate_error,
)
from mcp_eregistrations_ds.server import mcp


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def ds_health(
    instance: str | None = None,
) -> dict[str, Any]:
    """Check DS instance health and component status.

    No authentication required.

    Args:
        instance: Instance profile name.

    Returns:
        dict with version, branch, build_type, redis,
        database, minio.
    """
    try:
        async with DSClient.for_instance(instance) as client:
            data = await client.get("/status")
    except DSClientError as e:
        raise translate_error(e, resource_type="health") from e

    return {
        "version": data.get("version"),
        "branch": data.get("branch"),
        "build_type": data.get("build_type"),
        "redis": data.get("redis"),
        "database": data.get("database"),
        "minio": data.get("minio"),
    }


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False))
async def ds_auth_login(
    username: str,
    password: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Authenticate with DS via Keycloak password grant.

    Stores token for subsequent DS API calls. Token is shared
    across all eRegistrations MCP servers via OS keyring.

    Args:
        username: Keycloak username (email).
        password: Keycloak password.
        instance: Instance profile name.

    Returns:
        dict with authenticated, instance, username.
    """
    if instance is None:
        raise ToolError(
            "No instance specified. Pass instance='<name>'. "
            "Use ds_instance_list to see available instances."
        )

    config = get_instance_config(instance, component="ds")

    keycloak_url = config.get("keycloak_url")
    keycloak_realm = config.get("keycloak_realm")
    keycloak_client_id = config.get("keycloak_client_id", "mcp-eregistrations-bpa")

    if not keycloak_url or not keycloak_realm:
        raise ToolError(
            "Keycloak not configured. Set KEYCLOAK_URL and "
            "KEYCLOAK_REALM env vars or register the instance "
            "with ds_instance_add."
        )

    try:
        result = await keycloak_password_grant(
            keycloak_url=keycloak_url,
            realm=keycloak_realm,
            client_id=keycloak_client_id,
            username=username,
            password=password,
        )
    except AuthenticationError as e:
        raise ToolError(str(e)) from e

    access_token = result.get("access_token")
    if not access_token:
        raise ToolError("No access_token in Keycloak response.")

    # Discover token endpoint for refresh token storage
    token_endpoint = (
        f"{keycloak_url.rstrip('/')}/realms/{keycloak_realm}"
        f"/protocol/openid-connect/token"
    )

    # Store in both DS local cache and shared keyring
    store_ds_token(instance, access_token)
    store_shared_tokens(
        instance,
        access_token=access_token,
        refresh_token=result.get("refresh_token"),
        token_endpoint=token_endpoint,
        client_id=keycloak_client_id,
    )

    return {
        "authenticated": True,
        "instance": instance,
        "username": username,
    }


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def business_entity_list(
    page: int = 1,
    instance: str | None = None,
) -> dict[str, Any]:
    """List business entities. Requires authentication.

    Args:
        page: Page number (default: 1).
        instance: Instance profile name.

    Returns:
        dict with items, count, page, page_size, has_next.
    """
    try:
        async with DSClient.for_instance(instance) as client:
            result = await client.get_paginated(
                "/backend/businessentity",
                params={"page": page},
            )
    except DSClientError as e:
        raise translate_error(e, resource_type="business_entity") from e

    return result
