"""Test @require_approval with LangChain tool calling."""

import json

import httpx
import respx
from langchain_core.tools import tool

from primitif import Primitif
from primitif.approval import ApprovalRequest

APPROVAL = "https://api.approval.primitif.ai"


@respx.mock
def test_langchain_tool_with_approval():
    """Agent calls a tool → decorator intercepts → approval request created."""
    respx.post(f"{APPROVAL}/v1/requests").mock(
        return_value=httpx.Response(200, json={
            "id": "ar_lc1",
            "action": "Send invoice",
            "context": {"client": "Acme", "amount": 45000},
            "status": "pending",
            "approval_url": "https://dash.primitif.ai/approve/ar_lc1",
            "created_at": "2025-01-01T00:00:00Z",
        })
    )

    p = Primitif(api_key="pk_live_test12345678901234567890123456")

    @tool
    @p.approval.require_approval()
    def send_invoice(client: str, amount: int) -> str:
        """Send an invoice to a client."""
        return f"Invoice sent to {client} for ${amount}"

    # Agent invokes the tool — gets approval request, not execution
    result = send_invoice.invoke({"client": "Acme", "amount": 45000})

    assert isinstance(result, ApprovalRequest)
    assert result.status == "pending"
    assert result.id == "ar_lc1"

    # Verify the API received the right payload
    body = json.loads(respx.calls[0].request.content)
    assert body["action"] == "Send invoice"
    assert body["context"] == {"client": "Acme", "amount": 45000}

    p.close()


@respx.mock
def test_langchain_tool_dispatch_on_approval():
    """Webhook fires → dispatch() executes the original tool."""
    respx.post(f"{APPROVAL}/v1/requests").mock(
        return_value=httpx.Response(200, json={
            "id": "ar_lc2",
            "action": "Send invoice",
            "context": {"client": "Acme", "amount": 45000},
            "status": "pending",
            "approval_url": "https://dash.primitif.ai/approve/ar_lc2",
            "created_at": "2025-01-01T00:00:00Z",
        })
    )

    p = Primitif(api_key="pk_live_test12345678901234567890123456")
    executed = []

    @tool
    @p.approval.require_approval()
    def send_invoice(client: str, amount: int) -> str:
        """Send an invoice to a client."""
        executed.append({"client": client, "amount": amount})
        return f"Invoice sent to {client} for ${amount}"

    # 1. Agent calls the tool — intercepted
    result = send_invoice.invoke({"client": "Acme", "amount": 45000})
    assert result.status == "pending"
    assert executed == []  # nothing executed yet

    # 2. Webhook fires with approved status — dispatch executes the tool
    webhook_event = {
        "action": "Send invoice",
        "status": "approved",
        "context": {"client": "Acme", "amount": 45000},
    }
    output = p.approval.dispatch(webhook_event)

    assert output == "Invoice sent to Acme for $45000"
    assert executed == [{"client": "Acme", "amount": 45000}]

    p.close()


@respx.mock
def test_langchain_tool_rejected():
    """Rejected approval → dispatch() does nothing."""
    respx.post(f"{APPROVAL}/v1/requests").mock(
        return_value=httpx.Response(200, json={
            "id": "ar_lc3",
            "action": "Delete account",
            "context": {"user_id": 42},
            "status": "pending",
            "approval_url": "https://dash.primitif.ai/approve/ar_lc3",
            "created_at": "2025-01-01T00:00:00Z",
        })
    )

    p = Primitif(api_key="pk_live_test12345678901234567890123456")
    executed = []

    @tool
    @p.approval.require_approval()
    def delete_account(user_id: int) -> str:
        """Delete a user account."""
        executed.append(user_id)
        return f"Account {user_id} deleted"

    # Agent calls the tool
    result = delete_account.invoke({"user_id": 42})
    assert result.status == "pending"

    # Human rejects — dispatch does nothing
    webhook_event = {
        "action": "Delete account",
        "status": "rejected",
        "context": {"user_id": 42},
    }
    assert p.approval.dispatch(webhook_event) is None
    assert executed == []

    p.close()
