from unittest.mock import Mock, patch

from deribit_api import DeribitClient


def rpc_response(payload, status_code=200):
    response = Mock()
    response.status_code = status_code
    response.json.return_value = payload
    response.text = str(payload)
    return response


@patch("deribit_api.time.sleep", return_value=None)
@patch("deribit_api.requests.post")
def test_rate_limit_is_classified_and_retried(post, _sleep):
    post.side_effect = [
        rpc_response(
            {
                "jsonrpc": "2.0",
                "error": {"code": 10028, "message": "too_many_requests"},
            }
        ),
        rpc_response({"jsonrpc": "2.0", "result": {"index_price": 50_000}}),
    ]
    client = DeribitClient("id", "secret", testnet=True)

    result = client._call("public/get_index_price", max_retries=2)

    assert result["success"] is True
    assert post.call_count == 2


@patch("deribit_api.requests.post")
def test_insufficient_funds_is_not_retried(post):
    post.return_value = rpc_response(
        {
            "jsonrpc": "2.0",
            "error": {"code": 10009, "message": "not_enough_funds"},
        }
    )
    client = DeribitClient("id", "secret", testnet=True)

    result = client._call("public/test", max_retries=4)

    assert result["success"] is False
    assert result["error_category"] == "insufficient_funds"
    assert result["is_retryable"] is False
    assert post.call_count == 1


@patch("deribit_api.time.sleep", return_value=None)
@patch("deribit_api.requests.post")
def test_auth_failure_preserves_real_error_instead_of_synthetic_token_error(
    post, _sleep
):
    post.return_value = rpc_response(
        {
            "jsonrpc": "2.0",
            "error": {"code": 10028, "message": "too_many_requests"},
        }
    )
    client = DeribitClient("id", "secret", testnet=True)

    result = client._call("private/get_account_summary", max_retries=1)

    assert result["success"] is False
    assert result["error_code"] == 10028
    assert result["error_category"] == "rate_limit"
    assert result["error"]["message"] == "too_many_requests"


@patch("deribit_api.requests.post")
def test_http_400_json_rpc_error_is_classified_without_http_retries(post):
    post.return_value = rpc_response(
        {
            "jsonrpc": "2.0",
            "error": {"code": 10009, "message": "not_enough_funds"},
        },
        status_code=400,
    )
    client = DeribitClient("id", "secret", testnet=True)

    result = client._call("public/test", max_retries=4)

    assert result["error_category"] == "insufficient_funds"
    assert post.call_count == 1
