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

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)


# -- payouts.create() ----------------------------------------------------------


@resp_mock.activate
def test_create_posts_to_payout(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payout",
        body=api_response({
            "transactionId": "po_1",
            "status": "PROCESSING",
            "amount": "100",
            "processingFee": "1.5",
        }),
        content_type="application/json",
    )

    result = client.payouts.create(
        amount="100",
        destination_address="TXyz456",
    )

    assert len(resp_mock.calls) == 1
    req = resp_mock.calls[0].request
    assert req.url == f"{BASE_URL}/payout"
    assert req.method == "POST"

    body = json.loads(req.body)
    assert body["amount"] == "100"
    assert body["destinationAddress"] == "TXyz456"
    assert body["currency"] == "USDT_TRC20"
    assert body["chain"] == "TRON"
    assert req.headers["X-Api-Key"] == API_KEY

    assert result["transactionId"] == "po_1"
    assert result["status"] == "PROCESSING"


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

    client.payouts.create(
        amount="50",
        destination_address="TAddr1",
        idempotency_key="idem_abc123",
    )

    req = resp_mock.calls[0].request
    assert req.headers["Idempotency-Key"] == "idem_abc123"


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

    client.payouts.create(
        amount="200",
        destination_address="TAddr2",
        external_ref="order_99",
        metadata={"orderId": "99"},
    )

    req = resp_mock.calls[0].request
    body = json.loads(req.body)
    assert body["externalRef"] == "order_99"
    assert body["metadata"] == {"orderId": "99"}


# -- payouts.get() -------------------------------------------------------------


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

    result = client.payouts.get("po_abc")

    req = resp_mock.calls[0].request
    assert req.url == f"{BASE_URL}/payout/po_abc"
    assert req.method == "GET"
    assert result["id"] == "po_abc"
    assert result["status"] == "CONFIRMED"


# -- payouts.list() ------------------------------------------------------------


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

    client.payouts.list(page=1, limit=20, status="CONFIRMED")

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


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

    client.payouts.list(cursor="cur_xyz", sort="createdAt:desc")

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


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

    client.payouts.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


# -- payouts.estimate() -------------------------------------------------------


@resp_mock.activate
def test_estimate_posts_to_payout_estimate(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payout/estimate",
        body=api_response({
            "fee": "1.5",
            "totalAmount": "101.5",
            "estimatedTime": "5 minutes",
        }),
        content_type="application/json",
    )

    result = client.payouts.estimate(
        amount="100",
        currency="USDT_TRC20",
        chain="TRON",
        destination_address="TAddr3",
    )

    assert len(resp_mock.calls) == 1
    req = resp_mock.calls[0].request
    assert "/payout/estimate" in req.url
    assert req.method == "POST"

    body = json.loads(req.body)
    assert body["amount"] == "100"
    assert body["currency"] == "USDT_TRC20"
    assert body["chain"] == "TRON"
    assert body["destinationAddress"] == "TAddr3"


@resp_mock.activate
def test_estimate_returns_unwrapped_data(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payout/estimate",
        body=api_response({
            "fee": "2.0",
            "totalAmount": "102.0",
        }),
        content_type="application/json",
    )

    result = client.payouts.estimate(amount="100")

    # The resource method should unwrap res["data"], so result is the inner dict
    assert result["fee"] == "2.0"
    assert result["totalAmount"] == "102.0"


@resp_mock.activate
def test_estimate_minimal_body(client):
    resp_mock.add(
        resp_mock.POST,
        f"{BASE_URL}/payout/estimate",
        body=api_response({"fee": "1.0"}),
        content_type="application/json",
    )

    client.payouts.estimate(amount="50")

    req = resp_mock.calls[0].request
    body = json.loads(req.body)
    assert body == {"amount": "50"}
