"""MCP tools for DS file/application pipeline operations.

Provides read-only tools for listing, inspecting, and querying
application files, process state, KYC status, and payments.
"""

from __future__ import annotations

from typing import Any

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

from mcp_eregistrations_ds.ds_client import (
    DSClient,
    DSClientError,
    DSNotFoundError,
    translate_error,
)
from mcp_eregistrations_ds.server import mcp
from mcp_eregistrations_ds.tools.payments import _summarize_transaction


def _summarize_file(item: dict[str, Any]) -> dict[str, Any]:
    """Build a summary dict for a file list item.

    Args:
        item: Raw file object from API.

    Returns:
        Simplified summary dict.
    """
    user = item.get("user")
    return {
        "file_id": item.get("file_id"),
        "state": item.get("state"),
        "process_instance_id": item.get("process_instance_id"),
        "service_id": item.get("service_id"),
        "service_name": item.get("service_name"),
        "username": user.get("username") if isinstance(user, dict) else None,
        "locked": item.get("locked"),
        "created_at": item.get("created_at"),
        "modified_at": item.get("modified_at"),
        "submitted_at": item.get("submitted_at"),
    }


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def file_list(
    state: str | None = None,
    service_id: str | None = None,
    username: str | None = None,
    page: int = 1,
    instance: str | None = None,
) -> dict[str, Any]:
    """List application files with optional filters. Use file_get for full details.

    Args:
        state: Filter by file state (e.g., "revision").
        service_id: Filter by service ID.
        username: Filter by applicant username.
        page: Page number (default: 1).
        instance: Instance profile name.

    Returns:
        dict with items (summary fields only), count, page, page_size, has_next.
    """
    params: dict[str, Any] = {"page": page}
    if state is not None:
        params["state"] = state
    if service_id is not None:
        params["service_id"] = service_id
    if username is not None:
        params["user__username"] = username

    try:
        async with DSClient.for_instance(instance) as client:
            data = await client.get_paginated(
                "/backend/admin/files", params=params, timeout=60.0
            )
    except DSClientError as e:
        raise translate_error(e, resource_type="file") from e

    data["items"] = [_summarize_file(item) for item in data.get("items", [])]
    return data


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def file_get(
    file_id: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get details of a single application file.

    Args:
        file_id: The file ID to retrieve.
        instance: Instance profile name.

    Returns:
        dict with file details.
    """
    try:
        async with DSClient.for_instance(instance) as client:
            try:
                data: dict[str, Any] = await client.get(
                    f"/backend/admin/files/{file_id}"
                )
            except DSNotFoundError:
                raise ToolError(
                    f"File '{file_id}' not found. Use file_list to find valid file IDs."
                )
    except DSClientError as e:
        raise translate_error(e, resource_type="file", resource_id=file_id) from e

    return data


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def file_data_get(
    file_id: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get form submission data for a file.

    Args:
        file_id: The file ID to retrieve data for.
        instance: Instance profile name.

    Returns:
        dict with file_id and form_data (always a list).
    """
    try:
        async with DSClient.for_instance(instance) as client:
            try:
                data = await client.get(f"/backend/files/{file_id}/data")
            except DSNotFoundError:
                raise ToolError(
                    f"File '{file_id}' not found. Use file_list to find valid file IDs."
                )
    except DSClientError as e:
        raise translate_error(e, resource_type="file", resource_id=file_id) from e

    return {
        "file_id": file_id,
        "form_data": data if isinstance(data, list) else [data],
    }


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def file_process_state(
    process_id: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get current Camunda process variables for a file.

    Args:
        process_id: The Camunda process instance ID.
        instance: Instance profile name.

    Returns:
        dict with process_id and current process variables.
    """
    try:
        async with DSClient.for_instance(instance) as client:
            try:
                data = await client.get(
                    f"/backend/process/{process_id}/camunda-variables"
                )
            except DSNotFoundError:
                raise ToolError(
                    f"Process '{process_id}' not found. "
                    "Check the process ID from the file details."
                )
    except DSClientError as e:
        raise translate_error(e, resource_type="process", resource_id=process_id) from e

    result: dict[str, Any] = {"process_id": process_id}
    if isinstance(data, dict):
        result.update(data)
    return result


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def file_process_history(
    process_id: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get historical Camunda process variables for a file.

    Args:
        process_id: The Camunda process instance ID.
        instance: Instance profile name.

    Returns:
        dict with process_id and historical process variables.
    """
    try:
        async with DSClient.for_instance(instance) as client:
            try:
                data = await client.get(
                    f"/backend/process/{process_id}/historical-camunda-variables"
                )
            except DSNotFoundError:
                raise ToolError(
                    f"Process '{process_id}' not found. "
                    "Check the process ID from the file details."
                )
    except DSClientError as e:
        raise translate_error(e, resource_type="process", resource_id=process_id) from e

    result: dict[str, Any] = {"process_id": process_id}
    if isinstance(data, dict):
        result.update(data)
    return result


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def file_kyc_status(
    file_id: str,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get KYC verification status for a file.

    Extracts kyc-prefixed fields from the file record.

    Args:
        file_id: The file ID to check KYC status for.
        instance: Instance profile name.

    Returns:
        dict with file_id and kyc fields, or kyc_status
        "no_kyc_data" if none found.
    """
    try:
        async with DSClient.for_instance(instance) as client:
            try:
                data = await client.get(f"/backend/admin/files/{file_id}")
            except DSNotFoundError:
                raise ToolError(
                    f"File '{file_id}' not found. Use file_list to find valid file IDs."
                )
    except DSClientError as e:
        raise translate_error(e, resource_type="file", resource_id=file_id) from e

    # KYC fields live inside the "data" JSONField, not at top level
    inner = (data.get("data") or {}) if isinstance(data, dict) else {}
    kyc_fields: dict[str, Any] = {
        k: v for k, v in inner.items() if k.startswith("kyc_")
    }

    if not kyc_fields:
        return {"file_id": file_id, "kyc_status": "no_kyc_data"}

    return {"file_id": file_id, **kyc_fields}


@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def file_payment_status(
    file_id: str,
    page: int = 1,
    instance: str | None = None,
) -> dict[str, Any]:
    """Get payment transactions for a file.

    Args:
        file_id: The file ID to check payments for.
        page: Page number (default: 1).
        instance: Instance profile name.

    Returns:
        dict with items, count, page, page_size, has_next.
    """
    params: dict[str, Any] = {"file_id": file_id, "page": page}

    try:
        async with DSClient.for_instance(instance) as client:
            data = await client.get_paginated(
                "/backend/payment_transaction", params=params
            )
    except DSClientError as e:
        raise translate_error(e, resource_type="payment", resource_id=file_id) from e

    data["items"] = [_summarize_transaction(item) for item in data.get("items", [])]
    return data
