"""
Binance Sub Account REST API

OpenAPI Specification for the Binance Sub Account REST API
The version of the OpenAPI document: 1.0.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""

import json
import pytest
import requests

from unittest.mock import MagicMock, patch
from urllib.parse import parse_qs

from binance_common.configuration import ConfigurationRestAPI
from binance_common.errors import RequiredError
from binance_common.utils import normalize_query_values, is_one_of_model, snake_to_camel

from binance_sdk_sub_account.rest_api.api import AssetManagementApi
from binance_sdk_sub_account.rest_api.models import FuturesTransferForSubAccountResponse
from binance_sdk_sub_account.rest_api.models import (
    GetDetailOnSubAccountsFuturesAccountResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    GetDetailOnSubAccountsFuturesAccountV2Response,
)
from binance_sdk_sub_account.rest_api.models import (
    GetDetailOnSubAccountsMarginAccountResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    GetMovePositionHistoryForSubAccountResponse,
)
from binance_sdk_sub_account.rest_api.models import GetSubAccountDepositAddressResponse
from binance_sdk_sub_account.rest_api.models import GetSubAccountDepositHistoryResponse
from binance_sdk_sub_account.rest_api.models import (
    GetSummaryOfSubAccountsFuturesAccountResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    GetSummaryOfSubAccountsFuturesAccountV2Response,
)
from binance_sdk_sub_account.rest_api.models import (
    GetSummaryOfSubAccountsMarginAccountResponse,
)
from binance_sdk_sub_account.rest_api.models import MarginTransferForSubAccountResponse
from binance_sdk_sub_account.rest_api.models import MovePositionForSubAccountResponse
from binance_sdk_sub_account.rest_api.models import QuerySubAccountAssetsResponse
from binance_sdk_sub_account.rest_api.models import (
    QuerySubAccountAssetsAssetManagementResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    QuerySubAccountFuturesAssetTransferHistoryResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    QuerySubAccountSpotAssetTransferHistoryResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    QuerySubAccountSpotAssetsSummaryResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    QueryUniversalTransferHistoryResponse,
)
from binance_sdk_sub_account.rest_api.models import (
    SubAccountFuturesAssetTransferResponse,
)
from binance_sdk_sub_account.rest_api.models import SubAccountTransferHistoryResponse
from binance_sdk_sub_account.rest_api.models import TransferToMasterResponse
from binance_sdk_sub_account.rest_api.models import (
    TransferToSubAccountOfSameMasterResponse,
)
from binance_sdk_sub_account.rest_api.models import UniversalTransferResponse


from binance_sdk_sub_account.rest_api.models import (
    MovePositionForSubAccountOrderArgsParameterInner,
)


class TestAssetManagementApi:
    @pytest.fixture(autouse=True)
    def setup_client(self):
        """Setup a client instance with mocked session before each test method."""
        self.mock_session = MagicMock(spec=requests.Session)
        config = ConfigurationRestAPI(
            api_key="test-api-key",
            api_secret="test-api-secret",
        )
        self.client = AssetManagementApi(
            configuration=config, session=self.mock_session
        )

    def set_mock_response(self, data: dict = {}, status_code=200, headers=None):
        """Helper method to setup mock response for the client's session request."""
        if headers is None:
            headers = {}

        mock_response = MagicMock()
        mock_response.status_code = status_code
        mock_response.json.return_value = data
        mock_response.text = json.dumps(data)
        mock_response.headers = headers

        self.mock_session.request.return_value = mock_response

    @patch("binance_common.utils.get_signature")
    def test_futures_transfer_for_sub_account_success(self, mock_get_signature):
        """Test futures_transfer_for_sub_account() successfully with required parameters only."""

        params = {
            "email": "sub-account-email@email.com",
            "asset": "asset_example",
            "amount": 1.0,
            "type": 56,
        }

        expected_response = {"txnId": "2966662589"}
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.futures_transfer_for_sub_account(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/sub-account/futures/transfer" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"
        assert normalized["email"] == "sub-account-email@email.com"
        assert normalized["asset"] == "asset_example"
        assert normalized["amount"] == 1.0
        assert normalized["type"] == 56

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(FuturesTransferForSubAccountResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof
            or is_list
            or hasattr(FuturesTransferForSubAccountResponse, "from_dict")
        ):
            expected = FuturesTransferForSubAccountResponse.from_dict(expected_response)
        else:
            expected = FuturesTransferForSubAccountResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_futures_transfer_for_sub_account_success_with_optional_params(
        self, mock_get_signature
    ):
        """Test futures_transfer_for_sub_account() successfully with optional parameters."""

        params = {
            "email": "sub-account-email@email.com",
            "asset": "asset_example",
            "amount": 1.0,
            "type": 56,
            "recv_window": 5000,
        }

        expected_response = {"txnId": "2966662589"}
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.futures_transfer_for_sub_account(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/sub-account/futures/transfer" in request_kwargs["url"]
        assert request_kwargs["method"] == "POST"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(FuturesTransferForSubAccountResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof
            or is_list
            or hasattr(FuturesTransferForSubAccountResponse, "from_dict")
        ):
            expected = FuturesTransferForSubAccountResponse.from_dict(expected_response)
        else:
            expected = FuturesTransferForSubAccountResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    def test_futures_transfer_for_sub_account_missing_required_param_email(self):
        """Test that futures_transfer_for_sub_account() raises RequiredError when 'email' is missing."""
        params = {
            "email": "sub-account-email@email.com",
            "asset": "asset_example",
            "amount": 1.0,
            "type": 56,
        }
        params["email"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'email'"):
            self.client.futures_transfer_for_sub_account(**params)

    def test_futures_transfer_for_sub_account_missing_required_param_asset(self):
        """Test that futures_transfer_for_sub_account() raises RequiredError when 'asset' is missing."""
        params = {
            "email": "sub-account-email@email.com",
            "asset": "asset_example",
            "amount": 1.0,
            "type": 56,
        }
        params["asset"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'asset'"):
            self.client.futures_transfer_for_sub_account(**params)

    def test_futures_transfer_for_sub_account_missing_required_param_amount(self):
        """Test that futures_transfer_for_sub_account() raises RequiredError when 'amount' is missing."""
        params = {
            "email": "sub-account-email@email.com",
            "asset": "asset_example",
            "amount": 1.0,
            "type": 56,
        }
        params["amount"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'amount'"):
            self.client.futures_transfer_for_sub_account(**params)

    def test_futures_transfer_for_sub_account_missing_required_param_type(self):
        """Test that futures_transfer_for_sub_account() raises RequiredError when 'type' is missing."""
        params = {
            "email": "sub-account-email@email.com",
            "asset": "asset_example",
            "amount": 1.0,
            "type": 56,
        }
        params["type"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'type'"):
            self.client.futures_transfer_for_sub_account(**params)

    def test_futures_transfer_for_sub_account_server_error(self):
        """Test that futures_transfer_for_sub_account() raises an error when the server returns an error."""

        params = {
            "email": "sub-account-email@email.com",
            "asset": "asset_example",
            "amount": 1.0,
            "type": 56,
        }

        mock_error = Exception("ResponseError")
        self.client.futures_transfer_for_sub_account = MagicMock(side_effect=mock_error)

        with pytest.raises(Exception, match="ResponseError"):
            self.client.futures_transfer_for_sub_account(**params)

    @patch("binance_common.utils.get_signature")
    def test_get_detail_on_sub_accounts_futures_account_success(
        self, mock_get_signature
    ):
        """Test get_detail_on_sub_accounts_futures_account() successfully with required parameters only."""

        params = {
            "email": "sub-account-email@email.com",
        }

        expected_response = {
            "email": "abc@test.com",
            "asset": "USDT",
            "assets": [
                {
                    "asset": "USDT",
                    "initialMargin": "0.00000000",
                    "maintenanceMargin": "0.00000000",
                    "marginBalance": "0.88308000",
                    "maxWithdrawAmount": "0.88308000",
                    "openOrderInitialMargin": "0.00000000",
                    "positionInitialMargin": "0.00000000",
                    "unrealizedProfit": "0.00000000",
                    "walletBalance": "0.88308000",
                }
            ],
            "canDeposit": True,
            "canTrade": True,
            "canWithdraw": True,
            "feeTier": 2,
            "maxWithdrawAmount": "0.88308000",
            "totalInitialMargin": "0.00000000",
            "totalMaintenanceMargin": "0.00000000",
            "totalMarginBalance": "0.88308000",
            "totalOpenOrderInitialMargin": "0.00000000",
            "totalPositionInitialMargin": "0.00000000",
            "totalUnrealizedProfit": "0.00000000",
            "totalWalletBalance": "0.88308000",
            "updateTime": 1576756674610,
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.get_detail_on_sub_accounts_futures_account(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/sub-account/futures/account" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["email"] == "sub-account-email@email.com"

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(GetDetailOnSubAccountsFuturesAccountResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof
            or is_list
            or hasattr(GetDetailOnSubAccountsFuturesAccountResponse, "from_dict")
        ):
            expected = GetDetailOnSubAccountsFuturesAccountResponse.from_dict(
                expected_response
            )
        else:
            expected = GetDetailOnSubAccountsFuturesAccountResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_get_detail_on_sub_accounts_futures_account_success_with_optional_params(
        self, mock_get_signature
    ):
        """Test get_detail_on_sub_accounts_futures_account() successfully with optional parameters."""

        params = {"email": "sub-account-email@email.com", "recv_window": 5000}

        expected_response = {
            "email": "abc@test.com",
            "asset": "USDT",
            "assets": [
                {
                    "asset": "USDT",
                    "initialMargin": "0.00000000",
                    "maintenanceMargin": "0.00000000",
                    "marginBalance": "0.88308000",
                    "maxWithdrawAmount": "0.88308000",
                    "openOrderInitialMargin": "0.00000000",
                    "positionInitialMargin": "0.00000000",
                    "unrealizedProfit": "0.00000000",
                    "walletBalance": "0.88308000",
                }
            ],
            "canDeposit": True,
            "canTrade": True,
            "canWithdraw": True,
            "feeTier": 2,
            "maxWithdrawAmount": "0.88308000",
            "totalInitialMargin": "0.00000000",
            "totalMaintenanceMargin": "0.00000000",
            "totalMarginBalance": "0.88308000",
            "totalOpenOrderInitialMargin": "0.00000000",
            "totalPositionInitialMargin": "0.00000000",
            "totalUnrealizedProfit": "0.00000000",
            "totalWalletBalance": "0.88308000",
            "updateTime": 1576756674610,
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.get_detail_on_sub_accounts_futures_account(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/sub-account/futures/account" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(GetDetailOnSubAccountsFuturesAccountResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof
            or is_list
            or hasattr(GetDetailOnSubAccountsFuturesAccountResponse, "from_dict")
        ):
            expected = GetDetailOnSubAccountsFuturesAccountResponse.from_dict(
                expected_response
            )
        else:
            expected = GetDetailOnSubAccountsFuturesAccountResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

    def test_get_detail_on_sub_accounts_futures_account_missing_required_param_email(
        self,
    ):
        """Test that get_detail_on_sub_accounts_futures_account() raises RequiredError when 'email' is missing."""
        params = {
            "email": "sub-account-email@email.com",
        }
        params["email"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'email'"):
            self.client.get_detail_on_sub_accounts_futures_account(**params)

    def test_get_detail_on_sub_accounts_futures_account_server_error(self):
        """Test that get_detail_on_sub_accounts_futures_account() raises an error when the server returns an error."""

        params = {
            "email": "sub-account-email@email.com",
        }

        mock_error = Exception("ResponseError")
        self.client.get_detail_on_sub_accounts_futures_account = MagicMock(
            side_effect=mock_error
        )

        with pytest.raises(Exception, match="ResponseError"):
            self.client.get_detail_on_sub_accounts_futures_account(**params)

    @patch("binance_common.utils.get_signature")
    def test_get_detail_on_sub_accounts_futures_account_v2_success(
        self, mock_get_signature
    ):
        """Test get_detail_on_sub_accounts_futures_account_v2() successfully with required parameters only."""

        params = {
            "email": "sub-account-email@email.com",
            "futures_type": 56,
        }

        expected_response = {
            "futureAccountResp": {
                "email": "abc@test.com",
                "assets": [
                    {
                        "asset": "USDT",
                        "initialMargin": "0.00000000",
                        "maintenanceMargin": "0.00000000",
                        "marginBalance": "0.88308000",
                        "maxWithdrawAmount": "0.88308000",
                        "openOrderInitialMargin": "0.00000000",
                        "positionInitialMargin": "0.00000000",
                        "unrealizedProfit": "0.00000000",
                        "walletBalance": "0.88308000",
                    }
                ],
                "canDeposit": True,
                "canTrade": True,
                "canWithdraw": True,
                "feeTier": 2,
                "maxWithdrawAmount": "0.88308000",
                "totalInitialMargin": "0.00000000",
                "totalMaintenanceMargin": "0.00000000",
                "totalMarginBalance": "0.88308000",
                "totalOpenOrderInitialMargin": "0.00000000",
                "totalPositionInitialMargin": "0.00000000",
                "totalUnrealizedProfit": "0.00000000",
                "totalWalletBalance": "0.88308000",
                "updateTime": 1576756674610,
            },
            "deliveryAccountResp": {
                "email": "abc@test.com",
                "assets": [
                    {
                        "asset": "BTC",
                        "initialMargin": "0.00000000",
                        "maintenanceMargin": "0.00000000",
                        "marginBalance": "0.88308000",
                        "maxWithdrawAmount": "0.88308000",
                        "openOrderInitialMargin": "0.00000000",
                        "positionInitialMargin": "0.00000000",
                        "unrealizedProfit": "0.00000000",
                        "walletBalance": "0.88308000",
                    }
                ],
                "canDeposit": True,
                "canTrade": True,
                "canWithdraw": True,
                "feeTier": 2,
                "updateTime": 1598959682001,
            },
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.get_detail_on_sub_accounts_futures_account_v2(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v2/sub-account/futures/account" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["email"] == "sub-account-email@email.com"
        assert normalized["futuresType"] == 56

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(GetDetailOnSubAccountsFuturesAccountV2Response)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof
            or is_list
            or hasattr(GetDetailOnSubAccountsFuturesAccountV2Response, "from_dict")
        ):
            expected = GetDetailOnSubAccountsFuturesAccountV2Response.from_dict(
                expected_response
            )
        else:
            expected = (
                GetDetailOnSubAccountsFuturesAccountV2Response.model_validate_json(
                    json.dumps(expected_response)
                )
            )

        assert response.data() == expected

    @patch("binance_common.utils.get_signature")
    def test_get_detail_on_sub_accounts_futures_account_v2_success_with_optional_params(
        self, mock_get_signature
    ):
        """Test get_detail_on_sub_accounts_futures_account_v2() successfully with optional parameters."""

        params = {
            "email": "sub-account-email@email.com",
            "futures_type": 56,
            "recv_window": 5000,
        }

        expected_response = {
            "futureAccountResp": {
                "email": "abc@test.com",
                "assets": [
                    {
                        "asset": "USDT",
                        "initialMargin": "0.00000000",
                        "maintenanceMargin": "0.00000000",
                        "marginBalance": "0.88308000",
                        "maxWithdrawAmount": "0.88308000",
                        "openOrderInitialMargin": "0.00000000",
                        "positionInitialMargin": "0.00000000",
                        "unrealizedProfit": "0.00000000",
                        "walletBalance": "0.88308000",
                    }
                ],
                "canDeposit": True,
                "canTrade": True,
                "canWithdraw": True,
                "feeTier": 2,
                "maxWithdrawAmount": "0.88308000",
                "totalInitialMargin": "0.00000000",
                "totalMaintenanceMargin": "0.00000000",
                "totalMarginBalance": "0.88308000",
                "totalOpenOrderInitialMargin": "0.00000000",
                "totalPositionInitialMargin": "0.00000000",
                "totalUnrealizedProfit": "0.00000000",
                "totalWalletBalance": "0.88308000",
                "updateTime": 1576756674610,
            },
            "deliveryAccountResp": {
                "email": "abc@test.com",
                "assets": [
                    {
                        "asset": "BTC",
                        "initialMargin": "0.00000000",
                        "maintenanceMargin": "0.00000000",
                        "marginBalance": "0.88308000",
                        "maxWithdrawAmount": "0.88308000",
                        "openOrderInitialMargin": "0.00000000",
                        "positionInitialMargin": "0.00000000",
                        "unrealizedProfit": "0.00000000",
                        "walletBalance": "0.88308000",
                    }
                ],
                "canDeposit": True,
                "canTrade": True,
                "canWithdraw": True,
                "feeTier": 2,
                "updateTime": 1598959682001,
            },
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.get_detail_on_sub_accounts_futures_account_v2(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v2/sub-account/futures/account" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"

        self.mock_session.request.assert_called_once()
        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(GetDetailOnSubAccountsFuturesAccountV2Response)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof
            or is_list
            or hasattr(GetDetailOnSubAccountsFuturesAccountV2Response, "from_dict")
        ):
            expected = GetDetailOnSubAccountsFuturesAccountV2Response.from_dict(
                expected_response
            )
        else:
            expected = (
                GetDetailOnSubAccountsFuturesAccountV2Response.model_validate_json(
                    json.dumps(expected_response)
                )
            )

        assert response.data() == expected

    def test_get_detail_on_sub_accounts_futures_account_v2_missing_required_param_email(
        self,
    ):
        """Test that get_detail_on_sub_accounts_futures_account_v2() raises RequiredError when 'email' is missing."""
        params = {
            "email": "sub-account-email@email.com",
            "futures_type": 56,
        }
        params["email"] = None

        with pytest.raises(RequiredError, match="Missing required parameter 'email'"):
            self.client.get_detail_on_sub_accounts_futures_account_v2(**params)

    def test_get_detail_on_sub_accounts_futures_account_v2_missing_required_param_futures_type(
        self,
    ):
        """Test that get_detail_on_sub_accounts_futures_account_v2() raises RequiredError when 'futures_type' is missing."""
        params = {
            "email": "sub-account-email@email.com",
            "futures_type": 56,
        }
        params["futures_type"] = None

        with pytest.raises(
            RequiredError, match="Missing required parameter 'futures_type'"
        ):
            self.client.get_detail_on_sub_accounts_futures_account_v2(**params)

    def test_get_detail_on_sub_accounts_futures_account_v2_server_error(self):
        """Test that get_detail_on_sub_accounts_futures_account_v2() raises an error when the server returns an error."""

        params = {
            "email": "sub-account-email@email.com",
            "futures_type": 56,
        }

        mock_error = Exception("ResponseError")
        self.client.get_detail_on_sub_accounts_futures_account_v2 = MagicMock(
            side_effect=mock_error
        )

        with pytest.raises(Exception, match="ResponseError"):
            self.client.get_detail_on_sub_accounts_futures_account_v2(**params)

    @patch("binance_common.utils.get_signature")
    def test_get_detail_on_sub_accounts_margin_account_success(
        self, mock_get_signature
    ):
        """Test get_detail_on_sub_accounts_margin_account() successfully with required parameters only."""

        params = {
            "email": "sub-account-email@email.com",
        }

        expected_response = {
            "email": "123@test.com",
            "marginLevel": "11.64405625",
            "totalAssetOfBtc": "6.82728457",
            "totalLiabilityOfBtc": "0.58633215",
            "totalNetAssetOfBtc": "6.24095242",
            "marginTradeCoeffVo": {
                "forceLiquidationBar": "1.10000000",
                "marginCallBar": "1.50000000",
                "normalBar": "2.00000000",
            },
            "marginUserAssetVoList": [
                {
                    "asset": "BTC",
                    "borrowed": "0.00000000",
                    "free": "0.00499500",
                    "interest": "0.00000000",
                    "locked": "0.00000000",
                    "netAsset": "0.00499500",
                },
                {
                    "asset": "BNB",
                    "borrowed": "201.66666672",
                    "free": "2346.50000000",
                    "interest": "0.00000000",
                    "locked": "0.00000000",
                    "netAsset": "2144.83333328",
                },
                {
                    "asset": "ETH",
                    "borrowed": "0.00000000",
                    "free": "0.00000000",
                    "interest": "0.00000000",
                    "locked": "0.00000000",
                    "netAsset": "0.00000000",
                },
                {
                    "asset": "USDT",
                    "borrowed": "0.00000000",
                    "free": "0.00000000",
                    "interest": "0.00000000",
                    "locked": "0.00000000",
                    "netAsset": "0.00000000",
                },
            ],
        }
        mock_get_signature.return_value = "mocked_signature"
        self.set_mock_response(expected_response)

        response = self.client.get_detail_on_sub_accounts_margin_account(**params)

        actual_call_args = self.mock_session.request.call_args
        request_kwargs = actual_call_args.kwargs
        parsed_params = parse_qs(request_kwargs["params"])
        camel_case_params = {snake_to_camel(k): v for k, v in params.items()}
        normalized = normalize_query_values(parsed_params, camel_case_params)

        self.mock_session.request.assert_called_once()
        mock_get_signature.assert_called_once()

        assert "url" in request_kwargs
        assert "signature" in parse_qs(request_kwargs["params"])
        assert "/sapi/v1/sub-account/margin/account" in request_kwargs["url"]
        assert request_kwargs["method"] == "GET"
        assert normalized["email"] == "sub-account-email@email.com"

        assert response is not None
        is_list = isinstance(expected_response, list)
        is_flat_list = (
            is_list and not isinstance(expected_response[0], list) if is_list else False
        )
        is_oneof = is_one_of_model(GetDetailOnSubAccountsMarginAccountResponse)

        if is_list and not is_flat_list:
            expected = expected_response
        elif (
            is_oneof
            or is_list
            or hasattr(GetDetailOnSubAccountsMarginAccountResponse, "from_dict")
        ):
            expected = GetDetailOnSubAccountsMarginAccountResponse.from_dict(
                expected_response
            )
        else:
            expected = GetDetailOnSubAccountsMarginAccountResponse.model_validate_json(
                json.dumps(expected_response)
            )

        assert response.data() == expected

