"""Client for interacting with the Fewsats API"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['Fewsats', 'Offer', 'L402Offers']

# %% ../nbs/00_core.ipynb 2
from fastcore.utils import *
import os
import httpx
from typing import Dict, Any, List
import json
from fastcore.basics import BasicRepr
from fastcore.utils import store_attr
from typing import List, Dict, Any

# %% ../nbs/00_core.ipynb 6
class Fewsats:
    "Client for interacting with the Fewsats API"
    def __init__(self,
                 api_key: str = None, # The API key for the Fewsats account
                 base_url: str = "https://api.fewsats.com"): # The Fewsats API base URL
        self.api_key = api_key or os.environ.get("FEWSATS_API_KEY")
        if not self.api_key:
            raise ValueError("The api_key client option must be set either by passing api_key to the client or by setting the FEWSATS_API_KEY environment variable")
        self.base_url = base_url
        self._httpx_client = httpx.Client()
        self._httpx_client.headers.update({"Authorization": f"Token {self.api_key}"})


# %% ../nbs/00_core.ipynb 9
@patch
def _request(self: Fewsats, 
             method: str, # The HTTP method to use
             path: str, # The path to request
             timeout: int = 10, # Timeout for the request in s
             **kwargs) -> Dict[str, Any]:
    "Makes an authenticated request to Fewsats API"
    url = f"{self.base_url}/{path}"
    return  self._httpx_client.request(method, url, timeout=timeout, **kwargs)

# %% ../nbs/00_core.ipynb 13
@patch
def me(self: Fewsats):
    "Retrieve the user's info."
    return self._request("GET", "v0/users/me")


# %% ../nbs/00_core.ipynb 16
@patch
def balance(self: Fewsats):
    "Retrieve the balance of the user's wallet."
    return self._request("GET", "v0/wallets")


# %% ../nbs/00_core.ipynb 19
@patch
def payment_methods(self: Fewsats) -> List[Dict[str, Any]]:
    "Retrieve the user's payment methods, raises an exception for error status codes."
    return self._request("GET", "v0/stripe/payment-methods")


# %% ../nbs/00_core.ipynb 23
@patch
def _preview_payment(self: Fewsats,
                    amount: str): # The amount in USD cents
    "Simulates a purchase, raises an exception for error status codes."
    assert amount.isdigit()
    return self._request("POST", "v0/l402/preview/purchase/amount", json={"amount_usd": amount})


# %% ../nbs/00_core.ipynb 26
@patch
def create_offers(self:Fewsats,
                 offers:List[Dict[str,Any]], # List of offer objects following OfferCreateV0 schema
) -> dict:
    "Create offers for L402 payment server"
    return self._request("POST", "v0/l402/offers", json={"offers": offers})

# %% ../nbs/00_core.ipynb 29
@patch
def get_payment_details(self:Fewsats,
                       payment_request_url:str,
                       offer_id:str,
                       payment_method:str,
                       payment_context_token:str,
                       ) -> dict:
    data = {"offer_id": offer_id, "payment_method": payment_method, "payment_context_token": payment_context_token}
    return httpx.post(payment_request_url, json=data)


# %% ../nbs/00_core.ipynb 33
@patch
def get_payment_status(self:Fewsats,
                       payment_context_token:str,
                       ) -> dict:
    return self._request("GET", f"v0/l402/payment-status?payment_context_token={payment_context_token}")

# %% ../nbs/00_core.ipynb 35
@patch
def set_webhook(self:Fewsats,
                       webhook_url:str,
                       ) -> dict:
    return self._request("POST", f"v0/users/webhook/set", json={"webhook_url": webhook_url})

# %% ../nbs/00_core.ipynb 38
@patch
def pay_lightning(self: Fewsats, 
                  invoice: str, # lightning invoice
                  amount: int, # amount in cents
                  currency: str = "usd", # currency
                  description: str = "" ): # description of the payment 
    "Pay for a lightning invoice"
    data = {
        "invoice": invoice,
        "amount": amount,
        "currency": currency,
        "description": description
    }
    return self._request("POST", "v0/l402/purchases/lightning", json=data)

# %% ../nbs/00_core.ipynb 42
class Offer(BasicRepr):
    "Represents a single L402 offer"
    def __init__(self, 
                 offer_id: str,
                 amount: int,
                 currency: str,
                 description: str,
                 title: str,
                 payment_methods: List[str] = None,
                 type: str = "one-off"): 
        store_attr()

    def __repr__(self):
        return f"Offer: {self.title}\nID: {self.offer_id}\nAmount: {self.amount/100} {self.currency}\nDescription: {self.description}"
    
    @classmethod
    def from_dict(cls, d: Dict[str, Any]) -> 'Offer':
        "Create an Offer from a dictionary"
        return cls(**d)

class L402Offers(BasicRepr):
    "Represents the complete L402 offers schema"
    def __init__(self, 
                 offers: List[Offer],
                 payment_context_token: str,
                 payment_request_url: str,
                 version: str): 
        store_attr()
    
    def __repr__(self):
        offers_str = "\n".join([f"- {o.title} ({o.amount/100} {o.currency})" for o in self.offers])
        return f"L402 Offers:\n{offers_str}\nPayment URL: {self.payment_request_url}\nContext Token: {self.payment_context_token}"
    
    def as_dict(self) -> Dict[str, Any]:
        "Convert to dictionary format for API usage"
        return {
            'offers': [vars(o) for o in self.offers],
            'payment_context_token': self.payment_context_token,
            'payment_request_url': self.payment_request_url,
            'version': self.version
        }
    
    @classmethod
    def from_dict(cls, d: Dict[str, Any]) -> 'L402Offers':
        "Create an L402Offers object from a dictionary"
        offers = [Offer.from_dict(o) for o in d['offers']]
        return cls(
            offers=offers,
            payment_context_token=d['payment_context_token'],
            payment_request_url=d['payment_request_url'],
            version=d['version']
        )


# %% ../nbs/00_core.ipynb 46
@patch
def pay_offer(self:Fewsats,
        offer_id : str, # the offer id to pay for
        l402_offer: L402Offers, # a dictionary containing L402 offers
) -> dict: # payment status response
    """Pays an offer_id from the l402_offers. This tools requires the LLM caller to 
    support custom classes as parameters like Claudette does.

    Returns payment status response"""
    offer_dict = l402_offer.as_dict()
    data = {"offer_id": offer_id, **offer_dict}
    return self._request("POST", "v0/l402/purchases/from-offer", json=data)


# %% ../nbs/00_core.ipynb 50
@patch
def pay_offer_str(self:Fewsats,
        offer_id : str, # the offer id to pay for
        l402_offer: str, # JSON string containing L402 offers
) -> dict: # payment status response
    """Pays an offer_id from the l402_offers.

    The l402_offer parameter must be a JSON string with this structure:
    {
        'offers': [
            {
                'offer_id': 'test_offer_2',  # String identifier for the offer
                'amount': 1,                 # Numeric cost value
                'currency': 'usd',           # Currency code
                'description': 'Test offer', # Text description
                'title': 'Test Package'      # Title of the package
            }
        ],
        'payment_context_token': '60a8e027-8b8b-4ccf-b2b9-380ed0930283',  # Payment context token
        'payment_request_url': 'https://api.fewsats.com/v0/l402/payment-request',  # Payment URL
        'version': '0.2.2'  # API version
    }

    Returns payment status response"""
    # Parse JSON string to dictionary
    try:
        offer_data = json.loads(l402_offer)
        L402Offers.from_dict(offer_data) # we don't care about the return value, just validating the json input
    except json.JSONDecodeError:
        raise ValueError("Invalid JSON string provided for l402_offer")
    
    # Create payload with offer_id
    data = {"offer_id": offer_id, **offer_data}
    
    return self._request("POST", "v0/l402/purchases/from-offer", timeout=20, json=data)

# %% ../nbs/00_core.ipynb 54
@patch
def payment_info(self:Fewsats,
                  pid:str): # purchase id
    "Retrieve the details of a payment."
    return self._request("GET", f"v0/l402/outgoing-payments/{pid}")

# %% ../nbs/00_core.ipynb 57
@patch
def as_tools(self:Fewsats):
    "Return list of available tools for AI agents"
    return [
        self.me,
        self.balance,
        self.payment_methods,
        self.pay_offer_str,
        self.payment_info,
    ]
