"""Quattrino Python SDK (single file; only dependency: requests).

Usage:
    from quattrino import Quattrino
    q = Quattrino(base_url="https://YOUR-QUATTRINO-HOST",
                  api_key="qtrn_agent_key...")   # scoped agent credential
    pre = q.preflight(amount_minor=1999, merchant="openai")
    if pre.get("verdict", {}).get("can_purchase"):
        tx = q.request_transaction(amount_minor=1999, merchant="openai",
                                   idempotency_key="order-42")
"""
import uuid

import requests


class QuattrinoError(Exception):
    def __init__(self, status, payload):
        self.status, self.payload = status, payload
        super().__init__("Quattrino API error " + str(status) + ": " +
                         str(payload))


class Quattrino:
    def __init__(self, base_url, api_key, timeout=30):
        self.base = base_url.rstrip("/") + "/api/v1"
        self.session = requests.Session()
        self.session.headers["X-API-Key"] = api_key
        self.timeout = timeout

    def _call(self, method, path, json=None, params=None, headers=None):
        r = self.session.request(method, self.base + path, json=json,
                                 params=params, headers=headers or {},
                                 timeout=self.timeout)
        if r.status_code >= 400:
            try:
                raise QuattrinoError(r.status_code, r.json())
            except ValueError:
                raise QuattrinoError(r.status_code, r.text)
        return r.json()

    # ---- identity + purchase lifecycle ---------------------------------
    def whoami(self):
        return self._call("GET", "/agent/whoami")

    def preflight(self, amount_minor, merchant, **extra):
        """Everything knowable BEFORE spending: policy dry-run, routes,
        merchant trust, fees. Side-effect-free - never moves money."""
        body = dict(amount_minor=amount_minor, merchant=merchant, **extra)
        return self._call("POST", "/agent/preflight", json=body)

    def request_transaction(self, amount_minor, merchant,
                            idempotency_key=None, **extra):
        body = dict(amount_minor=amount_minor, merchant=merchant, **extra)
        return self._call("POST", "/agent/transactions", json=body,
                          headers={"Idempotency-Key":
                                   idempotency_key or str(uuid.uuid4())})

    def get_transaction(self, transaction_id):
        return self._call("GET", "/agent/transactions/" + transaction_id)

    def check_approval(self, approval_id):
        return self._call("GET", "/agent/approvals/" + approval_id)

    def submit_receipt(self, transaction_id, **receipt):
        return self._call("POST", "/agent/transactions/" + transaction_id +
                          "/receipt", json=receipt)

    # ---- marketplace ---------------------------------------------------
    def marketplace_search(self, query="", category=None):
        params = {"query": query}
        if category:
            params["category"] = category
        return self._call("GET", "/agent/marketplace/search", params=params)

    def get_service_quote(self, service_id, quantity=1):
        return self._call("POST", "/agent/services/" + service_id + "/quote",
                          json={"quantity": quantity})

    def negotiate(self, service_id, proposed_unit_price_minor, quantity=1):
        """Deterministic negotiation for NEGOTIATED-pricing services.
        ACCEPTED responses include quote["quote_id"] - purchase with it."""
        return self._call("POST", "/agent/services/" + service_id +
                          "/negotiations",
                          json={"proposed_unit_price_minor":
                                proposed_unit_price_minor,
                                "quantity": quantity})

    def respond_negotiation(self, negotiation_id, action="accept_counter",
                            proposed_unit_price_minor=None):
        body = {"action": action}
        if proposed_unit_price_minor is not None:
            body["proposed_unit_price_minor"] = proposed_unit_price_minor
        return self._call("POST", "/agent/negotiations/" + negotiation_id +
                          "/respond", json=body)

    def purchase_service(self, service_id, idempotency_key=None,
                         quantity=1, quote_id=None):
        body = {"quantity": quantity}
        if quote_id:
            body["quote_id"] = quote_id
        return self._call("POST", "/agent/services/" + service_id +
                          "/purchase", json=body,
                          headers={"Idempotency-Key":
                                   idempotency_key or str(uuid.uuid4())})
