"""Smoke tests sincronos para cada resource (uma chamada por endpoint)."""

from __future__ import annotations

import pytest
import respx
from httpx import Response

from abacapython import AbacaPay
from abacapython.models import (
    CreateCheckoutParams,
    CreateCouponParams,
    CreateCustomerParams,
    CreatePaymentLinkParams,
    CreatePayoutParams,
    CreatePixQrCodeParams,
    CreatePixTransferParams,
    CreateProductParams,
    CreateSubscriptionParams,
    CreateWebhookParams,
)

BASE = "https://api.test.abacatepay.local/v2"


def _env(data):
    return {"data": data, "success": True, "error": None}


@pytest.fixture
def client():
    cli = AbacaPay(api_key="abc_test", base_url=BASE, max_retries=0)
    yield cli
    cli.close()


# ---------------------------------------------------------------- customers
@respx.mock
def test_customers_create(client):
    route = respx.post(f"{BASE}/customers/create").respond(
        200, json=_env({"id": "cust_1", "email": "a@b.com", "taxId": "123"})
    )
    customer = client.customers.create({"email": "a@b.com", "tax_id": "123"})
    assert customer.id == "cust_1"
    assert customer.email == "a@b.com"
    body = route.calls[0].request.read()
    assert b'"email":"a@b.com"' in body
    assert b'"taxId":"123"' in body


@respx.mock
def test_customers_create_accepts_model(client):
    respx.post(f"{BASE}/customers/create").respond(
        200, json=_env({"id": "cust_2", "email": "b@c.com"})
    )
    customer = client.customers.create(CreateCustomerParams(email="b@c.com"))
    assert customer.id == "cust_2"


@respx.mock
def test_customers_list(client):
    respx.get(f"{BASE}/customers/list").respond(
        200,
        json=_env([{"id": "c1", "email": "a@b.com"}, {"id": "c2", "email": "x@y.com"}]),
    )
    customers = client.customers.list()
    assert [c.id for c in customers] == ["c1", "c2"]


@respx.mock
def test_customers_get(client):
    route = respx.get(f"{BASE}/customers/get", params={"id": "c1"}).respond(
        200, json=_env({"id": "c1", "email": "a@b.com"})
    )
    customer = client.customers.get(id="c1")
    assert customer.id == "c1"
    assert route.called


@respx.mock
def test_customers_delete(client):
    route = respx.post(f"{BASE}/customers/delete").respond(200, json=_env({"deleted": True}))
    client.customers.delete(id="c1")
    body = route.calls[0].request.read()
    assert b'"id":"c1"' in body


# ----------------------------------------------------------------- products
@respx.mock
def test_products_create(client):
    respx.post(f"{BASE}/products/create").respond(
        200,
        json=_env(
            {"id": "p1", "externalId": "ext_1", "name": "Plano", "price": 10000, "currency": "BRL"}
        ),
    )
    product = client.products.create(
        CreateProductParams(external_id="ext_1", name="Plano", price=10000, currency="BRL")
    )
    assert product.id == "p1"
    assert product.price == 10000


@respx.mock
def test_products_delete(client):
    respx.post(f"{BASE}/products/delete").respond(200, json=_env({"deleted": True}))
    client.products.delete(id="p1")


# ---------------------------------------------------------------- checkouts
@respx.mock
def test_checkouts_create(client):
    route = respx.post(f"{BASE}/checkouts/create").respond(
        200,
        json=_env(
            {
                "id": "chk_1",
                "url": "https://pay.abacatepay.com/chk_1",
                "status": "PENDING",
            }
        ),
    )
    checkout = client.checkouts.create(CreateCheckoutParams(items=[{"id": "p1", "quantity": 1}]))
    assert checkout.id == "chk_1"
    assert checkout.url.startswith("https://")
    body = route.calls[0].request.read()
    assert b'"items"' in body


@respx.mock
def test_checkouts_get(client):
    respx.get(f"{BASE}/checkouts/one", params={"id": "chk_1"}).respond(
        200, json=_env({"id": "chk_1", "status": "PAID"})
    )
    checkout = client.checkouts.get(id="chk_1")
    assert checkout.status == "PAID"


# ------------------------------------------------------------- payment_links
@respx.mock
def test_payment_links_create(client):
    respx.post(f"{BASE}/payment-links/create").respond(
        200, json=_env({"id": "pl_1", "url": "https://pay/abc"})
    )
    pl = client.payment_links.create(CreatePaymentLinkParams(items=[{"id": "p1", "quantity": 1}]))
    assert pl.id == "pl_1"


# ------------------------------------------------------------- pix_qrcodes
@respx.mock
def test_pix_qrcode_create_wraps_data(client):
    route = respx.post(f"{BASE}/transparents/create").respond(
        200,
        json=_env(
            {
                "id": "pix_1",
                "amount": 10000,
                "status": "PENDING",
                "brCode": "00020126...",
                "brCodeBase64": "iVBORw0...",
            }
        ),
    )
    pix = client.pix_qrcodes.create(CreatePixQrCodeParams(amount=10000, description="Pedido 42"))
    assert pix.id == "pix_1"
    assert pix.br_code.startswith("0002")
    body = route.calls[0].request.read()
    # API espera tudo aninhado em "data".
    assert b'"data":{' in body
    assert b'"amount":10000' in body


@respx.mock
def test_pix_qrcode_check(client):
    respx.get(f"{BASE}/transparents/check", params={"id": "pix_1"}).respond(
        200, json=_env({"id": "pix_1", "status": "PAID"})
    )
    pix = client.pix_qrcodes.check(id="pix_1")
    assert pix.status.value == "PAID"


@respx.mock
def test_pix_qrcode_simulate(client):
    respx.post(f"{BASE}/transparents/simulate-payment").respond(
        200, json=_env({"id": "pix_1", "status": "PAID"})
    )
    pix = client.pix_qrcodes.simulate_payment(id="pix_1")
    assert pix.status.value == "PAID"


# ------------------------------------------------------------------- coupons
@respx.mock
def test_coupons_toggle(client):
    respx.post(f"{BASE}/coupons/toggle").respond(
        200, json=_env({"id": "cp_1", "code": "DESC10", "active": False})
    )
    coupon = client.coupons.toggle(id="cp_1")
    assert coupon.active is False


@respx.mock
def test_coupons_create(client):
    respx.post(f"{BASE}/coupons/create").respond(
        200, json=_env({"id": "cp_1", "code": "DESC10", "active": True})
    )
    coupon = client.coupons.create(CreateCouponParams(code="DESC10"))
    assert coupon.code == "DESC10"


# ------------------------------------------------------------------- webhooks
@respx.mock
def test_webhooks_create(client):
    respx.post(f"{BASE}/webhooks/create").respond(
        200,
        json=_env(
            {
                "id": "wh_1",
                "name": "main",
                "endpoint": "https://meu.app/webhook",
                "events": ["checkout.completed"],
                "active": True,
            }
        ),
    )
    wh = client.webhooks.create(
        CreateWebhookParams(
            name="main",
            endpoint="https://meu.app/webhook",
            secret="s3cr3t",
            events=["checkout.completed"],
        )
    )
    assert wh.id == "wh_1"
    assert wh.events == ["checkout.completed"]


# -------------------------------------------------------------- subscriptions
@respx.mock
def test_subscriptions_create_enforces_one_item():
    with pytest.raises(Exception):
        CreateSubscriptionParams(items=[{"id": "p1", "quantity": 1}, {"id": "p2", "quantity": 1}])


@respx.mock
def test_subscriptions_cancel(client):
    respx.post(f"{BASE}/subscriptions/cancel").respond(
        200, json=_env({"id": "sub_1", "status": "CANCELLED"})
    )
    sub = client.subscriptions.cancel(id="sub_1")
    assert sub.status == "CANCELLED"


# ------------------------------------------------------------------- payouts
@respx.mock
def test_payouts_create(client):
    respx.post(f"{BASE}/payouts/create").respond(
        200, json=_env({"id": "po_1", "amount": 1000, "status": "PENDING"})
    )
    po = client.payouts.create(CreatePayoutParams(amount=1000, pix_key="x@y.com"))
    assert po.id == "po_1"


def test_payouts_create_validates_min():
    with pytest.raises(Exception):
        CreatePayoutParams(amount=100, pix_key="x@y.com")


# -------------------------------------------------------------- pix_transfers
@respx.mock
def test_pix_transfers_create(client):
    respx.post(f"{BASE}/pix/create").respond(
        200, json=_env({"id": "tr_1", "amount": 500, "status": "PENDING"})
    )
    tr = client.pix_transfers.create(CreatePixTransferParams(amount=500, pix_key="x@y.com"))
    assert tr.id == "tr_1"


# ---------------------------------------------------------------------- store
@respx.mock
def test_store_get(client):
    respx.get(f"{BASE}/store/get").respond(200, json=_env({"id": "s1", "name": "Minha Loja"}))
    store = client.store.get()
    assert store.name == "Minha Loja"


# ------------------------------------------------------------------- trustMRR
@respx.mock
def test_trust_mrr(client):
    respx.get(f"{BASE}/trustMRR/mrr", params={"slug": "loja"}).respond(
        200, json=_env({"slug": "loja", "mrr": 50000, "currency": "BRL"})
    )
    mrr = client.trust_mrr.mrr(slug="loja")
    assert mrr.mrr == 50000


@respx.mock
def test_list_normalizes_when_no_envelope(client):
    """Algumas listagens podem vir como array direto. Garantimos normalização."""
    respx.get(f"{BASE}/customers/list").mock(
        return_value=Response(200, json=[{"id": "x", "email": "x@y.com"}])
    )
    customers = client.customers.list()
    assert customers[0].id == "x"
