from typing import Any

import httpx

from app.config import get_settings


class PaymentNotConfiguredError(RuntimeError):
    def __init__(self) -> None:
        super().__init__("Payment provider is not configured")

    def to_dict(self) -> dict[str, str]:
        return {
            "code": "payment_provider_not_configured",
            "message": "Payment provider is not configured",
            "provider": "mollie",
            "action": "Set MOLLIE_API_KEY",
        }


_MOLLIE_API = "https://api.mollie.com/v2"


async def create_payment(
    order_id: str,
    amount_cents: int,
    description: str,
    redirect_url: str,
    client: httpx.AsyncClient | None = None,
) -> dict[str, Any]:
    settings = get_settings()
    if not settings.MOLLIE_API_KEY:
        raise PaymentNotConfiguredError()

    payload = {
        "amount": {
            "currency": "EUR",
            "value": f"{amount_cents / 100:.2f}",
        },
        "description": description,
        "redirectUrl": redirect_url,
        "metadata": {"order_id": order_id},
    }

    if client is None:
        async with httpx.AsyncClient() as owned_client:
            response = await owned_client.post(
                f"{_MOLLIE_API}/payments",
                json=payload,
                headers={
                    "Authorization": f"Bearer {settings.MOLLIE_API_KEY}",
                    "Content-Type": "application/json",
                },
            )
            response.raise_for_status()
            created_payment_data: dict[str, Any] = response.json()
    else:
        response = await client.post(
            f"{_MOLLIE_API}/payments",
            json=payload,
            headers={
                "Authorization": f"Bearer {settings.MOLLIE_API_KEY}",
                "Content-Type": "application/json",
            },
        )
        response.raise_for_status()
        created_payment_data = response.json()

    checkout_url: str = created_payment_data.get("_links", {}).get("checkout", {}).get("href", "")
    return {
        "payment_url": checkout_url,
        "payment_id": created_payment_data.get("id", ""),
    }


async def get_payment(payment_id: str, client: httpx.AsyncClient | None = None) -> dict[str, Any]:
    settings = get_settings()
    if not settings.MOLLIE_API_KEY:
        raise PaymentNotConfiguredError()

    if client is None:
        async with httpx.AsyncClient() as owned_client:
            response = await owned_client.get(
                f"{_MOLLIE_API}/payments/{payment_id}",
                headers={"Authorization": f"Bearer {settings.MOLLIE_API_KEY}"},
            )
            response.raise_for_status()
            payment_data: dict[str, Any] = response.json()
    else:
        response = await client.get(
            f"{_MOLLIE_API}/payments/{payment_id}",
            headers={"Authorization": f"Bearer {settings.MOLLIE_API_KEY}"},
        )
        response.raise_for_status()
        payment_data = response.json()
    return payment_data


async def list_payments(
    limit: int = 10,
    from_id: str | None = None,
    client: httpx.AsyncClient | None = None,
) -> dict[str, Any]:
    """List payments from Mollie — used as invoice history."""
    settings = get_settings()
    if not settings.MOLLIE_API_KEY:
        raise PaymentNotConfiguredError()

    params: dict[str, Any] = {"limit": limit}
    if from_id:
        params["from"] = from_id

    if client is None:
        async with httpx.AsyncClient() as owned_client:
            response = await owned_client.get(
                f"{_MOLLIE_API}/payments",
                params=params,
                headers={"Authorization": f"Bearer {settings.MOLLIE_API_KEY}"},
            )
            response.raise_for_status()
            payments_data: dict[str, Any] = response.json()
    else:
        response = await client.get(
            f"{_MOLLIE_API}/payments",
            params=params,
            headers={"Authorization": f"Bearer {settings.MOLLIE_API_KEY}"},
        )
        response.raise_for_status()
        payments_data = response.json()

    payments: list[dict[str, Any]] = payments_data.get("_embedded", {}).get("payments", [])
    return {
        "payments": payments,
        "count": payments_data.get("count", len(payments)),
        "next_cursor": payments_data.get("_links", {}).get("next", {}).get("href"),
    }
