"""Escrow tools — hold, release, refund, and check escrow status."""

from __future__ import annotations

import json

from mcp.server.fastmcp import FastMCP

from amrood_mcp.api_client import AmroodAPI
from amrood_mcp.auth import AuthState


def register_escrow_tools(mcp: FastMCP, api: AmroodAPI, auth: AuthState):
    """Register escrow tools on the MCP server."""

    async def _ensure_agent_id() -> str | None:
        if auth.agent_id:
            return auth.agent_id
        if auth.has_agent_key:
            try:
                data = await api.get("/v1/agents/me")
                auth.agent_id = data.get("agent_id")
                return auth.agent_id
            except Exception:
                return None
        return None

    @mcp.tool()
    async def amrood_escrow_hold(
        amount: float,
        reference: str | None = None,
        timeout_hours: float | None = None,
        attestor: str | None = None,
    ) -> str:
        """Hold funds in escrow before releasing them to another agent.

        Use this when you want to pay for a service but only release
        the funds after the work is done, or after a timeout.

        Three modes:
        - Basic hold: funds are held until you explicitly release or refund
        - Timed hold: auto-refunds if not released within timeout_hours
        - Attested hold: requires a third-party agent to attest before release

        Args:
            amount: Amount in INR to hold in escrow (must be > 0)
            reference: Optional reference describing what the escrow is for
            timeout_hours: If set, auto-refunds after this many hours
            attestor: If set, handle or ID of a third-party agent that must attest before release
        """
        agent_id = await _ensure_agent_id()
        if not agent_id:
            return "Error: No agent configured. Set AMROOD_AGENT_KEY or complete onboarding first."

        if attestor:
            resp = await api.post(
                f"/v1/agents/{agent_id}/escrow/hold-with-attestation",
                json={"amount": amount, "attestor_agent_id": attestor, "reference": reference},
            )
        elif timeout_hours:
            resp = await api.post(
                f"/v1/agents/{agent_id}/escrow/hold-with-timeout",
                json={"amount": amount, "timeout_hours": timeout_hours, "auto_action": "refund", "reference": reference},
            )
        else:
            resp = await api.post(
                f"/v1/agents/{agent_id}/escrow/hold",
                json={"amount": amount, "reference": reference},
            )

        if resp.status_code >= 400:
            try:
                err = resp.json()
            except Exception:
                err = resp.text
            return f"Escrow hold failed ({resp.status_code}): {json.dumps(err)}"

        data = resp.json()
        return json.dumps(data, indent=2)

    @mcp.tool()
    async def amrood_escrow_release(escrow_id: str, to: str) -> str:
        """Release escrowed funds to a recipient agent.

        After the work is done or the condition is met, release the held
        funds to the recipient. The recipient can be specified by handle
        or agent ID.

        Args:
            escrow_id: The escrow ID (e.g. "esc_xxx") from the hold response
            to: Recipient agent handle or ID to release funds to
        """
        agent_id = await _ensure_agent_id()
        if not agent_id:
            return "Error: No agent configured. Set AMROOD_AGENT_KEY or complete onboarding first."

        resp = await api.post(
            f"/v1/escrow/{escrow_id}/release",
            json={"to_agent_id": to},
        )
        if resp.status_code >= 400:
            try:
                err = resp.json()
            except Exception:
                err = resp.text
            return f"Escrow release failed ({resp.status_code}): {json.dumps(err)}"

        return json.dumps(resp.json(), indent=2)

    @mcp.tool()
    async def amrood_escrow_refund(escrow_id: str) -> str:
        """Refund escrowed funds back to the original sender.

        Use this if the work was not completed or the deal fell through.
        The full escrowed amount is returned to the sender's wallet.

        Args:
            escrow_id: The escrow ID (e.g. "esc_xxx") to refund
        """
        agent_id = await _ensure_agent_id()
        if not agent_id:
            return "Error: No agent configured. Set AMROOD_AGENT_KEY or complete onboarding first."

        resp = await api.post(f"/v1/escrow/{escrow_id}/refund")
        if resp.status_code >= 400:
            try:
                err = resp.json()
            except Exception:
                err = resp.text
            return f"Escrow refund failed ({resp.status_code}): {json.dumps(err)}"

        return json.dumps(resp.json(), indent=2)

    @mcp.tool()
    async def amrood_escrow_status(escrow_id: str) -> str:
        """Check the current status of an escrow.

        Returns whether the escrow is held, released, refunded, or expired,
        along with the amount, reference, and any conditions.

        Args:
            escrow_id: The escrow ID (e.g. "esc_xxx") to check
        """
        agent_id = await _ensure_agent_id()
        if not agent_id:
            return "Error: No agent configured. Set AMROOD_AGENT_KEY or complete onboarding first."

        try:
            data = await api.get(f"/v1/escrow/{escrow_id}")
            return json.dumps(data, indent=2)
        except Exception as e:
            return f"Failed to get escrow status: {e}"
