"""Gamma23 as a LangChain Tool

Shows how to wrap the Gamma23 SDK as a LangChain-compatible tool so that
an LLM agent can autonomously create spend intents and execute payments.

Requirements:
    pip install gamma23 langchain-core

Set GAMMA23_API_KEY in your environment before running.
"""

from __future__ import annotations

import json
from typing import Any

from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field

from gamma23 import Gamma23, Gamma23Error

client = Gamma23()


# ── Schemas ──────────────────────────────────────────────────────────────────

class SpendIntentInput(BaseModel):
    goal: str = Field(description="What the agent wants to purchase")
    budget: float = Field(description="Maximum amount to spend")
    currency: str = Field(default="GBP", description="ISO 4217 currency code")
    merchant: str | None = Field(default=None, description="Target merchant name")
    category: str | None = Field(default=None, description="Spending category")


class ExecuteSpendInput(BaseModel):
    intent_id: str = Field(description="The spend intent ID to execute")
    spend_token: str = Field(description="The spend token from the approved intent")


class CheckBudgetInput(BaseModel):
    agent_id: str = Field(description="The agent ID to check the budget for")


# ── Tool implementations ────────────────────────────────────────────────────

def create_spend_intent(
    goal: str,
    budget: float,
    currency: str = "GBP",
    merchant: str | None = None,
    category: str | None = None,
) -> str:
    """Create a Gamma23 spend intent for a purchase."""
    try:
        intent = client.spend_intents.create(
            goal=goal,
            budget=budget,
            currency=currency,
            merchant=merchant,
            category=category,
        )
        result: dict[str, Any] = {
            "intent_id": intent.id,
            "status": intent.status,
            "approved": bool(intent.spend_token),
        }
        if intent.spend_token:
            result["spend_token"] = intent.spend_token
        if intent.policy_decision:
            result["policy_reason"] = intent.policy_decision.reason
        return json.dumps(result)
    except Gamma23Error as e:
        return json.dumps({"error": str(e)})


def execute_spend(intent_id: str, spend_token: str) -> str:
    """Execute a previously approved spend intent."""
    try:
        result = client.spend_intents.execute(
            intent_id,
            spend_token=spend_token,
        )
        return json.dumps({
            "transaction_id": result.transaction_id,
            "status": result.status,
            "amount": result.amount,
            "currency": result.currency,
        })
    except Gamma23Error as e:
        return json.dumps({"error": str(e)})


def check_budget(agent_id: str) -> str:
    """Check the remaining budget for an agent."""
    try:
        budget = client.agents.get_budget(agent_id)
        return json.dumps({
            "total": budget.total_budget,
            "spent": budget.spent,
            "remaining": budget.remaining,
            "currency": budget.currency,
        })
    except Gamma23Error as e:
        return json.dumps({"error": str(e)})


# ── LangChain tools ─────────────────────────────────────────────────────────

gamma23_create_spend = StructuredTool.from_function(
    func=create_spend_intent,
    name="gamma23_create_spend_intent",
    description=(
        "Create a spend intent through Gamma23. Use this when you need to "
        "purchase something. Returns an intent ID and spend token if approved."
    ),
    args_schema=SpendIntentInput,
)

gamma23_execute_spend = StructuredTool.from_function(
    func=execute_spend,
    name="gamma23_execute_spend",
    description=(
        "Execute a previously approved spend intent. Requires the intent ID "
        "and spend token from gamma23_create_spend_intent."
    ),
    args_schema=ExecuteSpendInput,
)

gamma23_check_budget = StructuredTool.from_function(
    func=check_budget,
    name="gamma23_check_budget",
    description="Check the remaining budget for an AI agent.",
    args_schema=CheckBudgetInput,
)

# All tools, ready to pass to an agent
gamma23_tools = [gamma23_create_spend, gamma23_execute_spend, gamma23_check_budget]


if __name__ == "__main__":
    print("Available Gamma23 LangChain tools:")
    for tool in gamma23_tools:
        print(f"  - {tool.name}: {tool.description}")
