"""Integration tests for the Python SDK Payins resource."""

import json
import pytest
import responses as resp_mock

from zyndpay import ZyndPay
from zyndpay.errors import AuthenticationError, NotFoundError, ValidationError

API_KEY = "zyp_test_sk_test123"
BASE_URL = "https://api.zyndpay.io/v1"


@pytest.fixture
def client():
    return ZyndPay(api_key=API_KEY)


def api_response(data, meta=None):
    body = {"success": True, "data": data}
    if meta:
        body["meta"] = meta
    return json.dumps(body)


# ─── payins.create() ──────────────────────────────────────────────────────────

@resp_mock.activate
def test_create_posts_to_payin(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payin",
        body=api_response({
            "transactionId": "txn_1",
            "address": "TXyz123",
            "amount": "100",
            "paymentUrl": "https://pay.zyndpay.io/txn_1",
            "qrCodeUrl": "https://qr.example.com/txn_1",
            "status": "PENDING",
            "expiresAt": "2024-01-01T01:00:00.000Z",
        }),
        content_type="application/json",
    )

    result = client.payins.create(amount="100")

    assert len(resp_mock.calls) == 1
    req = resp_mock.calls[0].request
    assert req.url == f"{BASE_URL}/payin"
    assert req.method == "POST"
    assert json.loads(req.body)["amount"] == "100"
    assert req.headers["X-Api-Key"] == API_KEY

    assert result["transactionId"] == "txn_1"
    assert result["address"] == "TXyz123"


@resp_mock.activate
def test_create_appends_sandbox_param(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payin",
        body=api_response({"transactionId": "txn_sandbox"}),
        content_type="application/json",
    )

    client.payins.create(amount="50", sandbox=True)

    req = resp_mock.calls[0].request
    assert "sandbox=true" in req.url


@resp_mock.activate
def test_create_raises_validation_error_on_400(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payin",
        json={"success": False, "message": "amount must be at least 25 USDT"},
        status=400,
    )

    with pytest.raises(ValidationError):
        client.payins.create(amount="1")


@resp_mock.activate
def test_create_raises_auth_error_on_401(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payin",
        json={"success": False, "message": "Invalid API key"},
        status=401,
    )

    with pytest.raises(AuthenticationError):
        client.payins.create(amount="100")


# ─── payins.get() ─────────────────────────────────────────────────────────────

@resp_mock.activate
def test_get_fetches_payin_by_id(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/payin/txn_abc",
        body=api_response({"id": "txn_abc", "status": "CONFIRMED", "amount": "100"}),
        content_type="application/json",
    )

    result = client.payins.get("txn_abc")

    req = resp_mock.calls[0].request
    assert req.url == f"{BASE_URL}/payin/txn_abc"
    assert req.method == "GET"
    assert result["id"] == "txn_abc"


@resp_mock.activate
def test_get_raises_not_found_on_404(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/payin/nonexistent",
        json={"success": False, "message": "Not found"},
        status=404,
    )

    with pytest.raises(NotFoundError):
        client.payins.get("nonexistent")


# ─── payins.list() ────────────────────────────────────────────────────────────

@resp_mock.activate
def test_list_sends_query_params(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/payin",
        body=api_response([], {"page": 2, "limit": 10, "total": 0}),
        content_type="application/json",
    )

    client.payins.list(status="CONFIRMED", page=2, limit=10)

    req = resp_mock.calls[0].request
    assert "status=CONFIRMED" in req.url
    assert "page=2" in req.url
    assert "limit=10" in req.url


# ─── payins.simulate() ────────────────────────────────────────────────────────

@resp_mock.activate
def test_simulate_posts_to_sandbox_endpoint(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/sandbox/payin/txn_sim/simulate",
        body=api_response({"id": "txn_sim", "status": "CONFIRMED"}),
        content_type="application/json",
    )

    result = client.payins.simulate("txn_sim")

    req = resp_mock.calls[0].request
    assert "/sandbox/payin/txn_sim/simulate" in req.url
    assert req.method == "POST"
    assert result["id"] == "txn_sim"
