"""Integration tests for transactions, balances, payins (list updates), and withdrawals."""

import json

import pytest
import responses as resp_mock

from zyndpay import ZyndPay

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)


# -- transactions.export_pdf() ------------------------------------------------


@resp_mock.activate
def test_export_pdf_calls_correct_endpoint(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/transactions/export/pdf",
        body="%PDF-1.4 fake pdf content",
        content_type="application/pdf",
    )

    result = client.transactions.export_pdf()

    req = resp_mock.calls[0].request
    assert "/transactions/export/pdf" in req.url
    assert req.method == "GET"
    assert "%PDF" in result


@resp_mock.activate
def test_export_pdf_sends_filter_params(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/transactions/export/pdf",
        body="%PDF-1.4 content",
        content_type="application/pdf",
    )

    client.transactions.export_pdf(
        from_date="2024-01-01",
        to_date="2024-06-30",
        status="CONFIRMED",
        type="PAYIN",
    )

    req = resp_mock.calls[0].request
    assert "from=2024-01-01" in req.url
    assert "to=2024-06-30" in req.url
    assert "status=CONFIRMED" in req.url
    assert "type=PAYIN" in req.url


# -- balances.get_by_currency() ------------------------------------------------


@resp_mock.activate
def test_get_by_currency_calls_correct_endpoint(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/merchant/balances/ETH",
        body=api_response({"currency": "ETH", "balance": "5.25"}),
        content_type="application/json",
    )

    result = client.balances.get_by_currency("ETH")

    req = resp_mock.calls[0].request
    assert req.url == f"{BASE_URL}/merchant/balances/ETH"
    assert req.method == "GET"
    assert result["currency"] == "ETH"
    assert result["balance"] == "5.25"


@resp_mock.activate
def test_get_by_currency_usdt_trc20(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/merchant/balances/USDT_TRC20",
        body=api_response({"currency": "USDT_TRC20", "balance": "1000.00"}),
        content_type="application/json",
    )

    result = client.balances.get_by_currency("USDT_TRC20")

    assert result["currency"] == "USDT_TRC20"
    assert result["balance"] == "1000.00"


# -- payins.list() with comma-separated status ---------------------------------


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

    client.payins.list(status=["CONFIRMED", "OVERPAID"])

    req = resp_mock.calls[0].request
    # The status param should be comma-separated
    assert "status=CONFIRMED%2COVERPAID" in req.url or "status=CONFIRMED,OVERPAID" in req.url


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

    client.payins.list(status="PENDING")

    req = resp_mock.calls[0].request
    assert "status=PENDING" in req.url


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

    client.payins.list(cursor="abc", sort="createdAt:desc")

    req = resp_mock.calls[0].request
    assert "cursor=abc" in req.url
    assert "sort=createdAt" in req.url


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

    client.payins.list(from_date="2024-01-01", to_date="2024-12-31")

    req = resp_mock.calls[0].request
    assert "from=2024-01-01" in req.url
    assert "to=2024-12-31" in req.url


# -- withdrawals.list() with date range and filters ----------------------------


@resp_mock.activate
def test_withdrawals_list_date_range(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/withdrawals",
        body=api_response([], {"total": 0}),
        content_type="application/json",
    )

    client.withdrawals.list(from_date="2024-01-01", to_date="2024-12-31")

    req = resp_mock.calls[0].request
    assert "from=2024-01-01" in req.url
    assert "to=2024-12-31" in req.url


@resp_mock.activate
def test_withdrawals_list_cursor_and_sort(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/withdrawals",
        body=api_response([], {"total": 0}),
        content_type="application/json",
    )

    client.withdrawals.list(cursor="wc_123", sort="createdAt:asc")

    req = resp_mock.calls[0].request
    assert "cursor=wc_123" in req.url
    assert "sort=createdAt" in req.url


@resp_mock.activate
def test_withdrawals_list_basic_params(client):
    resp_mock.add(
        resp_mock.GET,
        f"{BASE_URL}/withdrawals",
        body=api_response([], {"total": 0}),
        content_type="application/json",
    )

    client.withdrawals.list(page=2, limit=10, status="PENDING")

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


# -- withdrawals.cancel() -----------------------------------------------------


@resp_mock.activate
def test_withdrawals_cancel_deletes_by_id(client):
    resp_mock.add(
        resp_mock.DELETE,
        f"{BASE_URL}/withdrawals/wd_cancel_1",
        body=api_response(None),
        content_type="application/json",
    )

    client.withdrawals.cancel("wd_cancel_1")

    req = resp_mock.calls[0].request
    assert req.url == f"{BASE_URL}/withdrawals/wd_cancel_1"
    assert req.method == "DELETE"
