"""Minimal Stripe API client for billing primitives."""

import httpx


class StripeApiError(Exception):
    """Raised when Stripe returns a non-success response."""

    def __init__(self, message: str, status_code: int, payload: dict | None = None):
        """Initialize Stripe API error details."""
        super().__init__(message)
        self.status_code = status_code
        self.payload = payload or {}


class StripeClient:
    """Thin wrapper over Stripe REST API endpoints."""

    def __init__(self, secret_key: str):
        """Initialize client with Stripe API secret key."""
        self._secret_key = secret_key
        self._base_url = "https://api.stripe.com/v1"

    async def _request(self, method: str, path: str, *, data: dict | None = None) -> dict:
        headers = {"Authorization": f"Bearer {self._secret_key}"}
        async with httpx.AsyncClient(timeout=20.0) as client:
            response = await client.request(
                method,
                f"{self._base_url}{path}",
                headers=headers,
                data=data,
            )

        if response.content:
            try:
                payload = response.json()
            except ValueError:
                payload = {"raw": response.text}
        else:
            payload = {}
        if response.status_code >= 400:
            message = payload.get("error", {}).get("message", "Stripe request failed")
            raise StripeApiError(message=message, status_code=response.status_code, payload=payload)
        return payload

    async def _post(self, path: str, data: dict) -> dict:
        return await self._request("POST", path, data=data)

    async def create_customer(
        self,
        *,
        email: str,
        name: str | None,
        user_uid: str,
    ) -> dict:
        """Create a Stripe customer."""
        data = {
            "email": email,
            "metadata[user_uid]": user_uid,
        }
        if name:
            data["name"] = name
        return await self._post("/customers", data=data)

    async def create_checkout_session(
        self,
        *,
        customer_id: str,
        price_id: str,
        success_url: str,
        cancel_url: str,
        user_uid: str,
        plan: str,
    ) -> dict:
        """Create a Stripe checkout session for a monthly subscription plan.

        Stamps both `user_uid` and the chosen `plan` into session and
        subscription metadata so webhooks can resolve the user and plan.
        """
        data = {
            "mode": "subscription",
            "customer": customer_id,
            "line_items[0][price]": price_id,
            "line_items[0][quantity]": "1",
            "success_url": success_url,
            "cancel_url": cancel_url,
            "client_reference_id": user_uid,
            "metadata[user_uid]": user_uid,
            "metadata[plan]": plan,
            "subscription_data[metadata][user_uid]": user_uid,
            "subscription_data[metadata][plan]": plan,
            "allow_promotion_codes": "true",
        }
        return await self._post("/checkout/sessions", data=data)

    async def create_billing_portal_session(self, *, customer_id: str, return_url: str) -> dict:
        """Create a Stripe billing portal session."""
        data = {
            "customer": customer_id,
            "return_url": return_url,
        }
        return await self._post("/billing_portal/sessions", data=data)

    async def get_price(self, price_id: str) -> dict:
        """Fetch Stripe price object by price id."""
        return await self._request("GET", f"/prices/{price_id}")
