"""
Binance Derivatives Trading COIN Futures WebSocket API

OpenAPI Specification for the Binance Derivatives Trading COIN Futures WebSocket API
The version of the OpenAPI document: 1.0.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""

from typing import Dict, Optional, TypeVar, Type, Union
from pydantic import BaseModel

from binance_common.configuration import ConfigurationWebSocketAPI
from binance_common.models import (
    WebsocketApiResponse,
)
from binance_common.signature import Signers
from binance_common.websocket import (
    WebSocketAPIBase,
    WebSocketConnection,
)

from .api.account_api import AccountApi
from .api.trade_api import TradeApi
from .api.user_data_streams_api import UserDataStreamsApi

from .models import AccountInformationResponse
from .models import FuturesAccountBalanceResponse
from .models import CancelOrderResponse
from .models import ModifyOrderResponse
from .models import NewOrderResponse
from .models import PositionInformationResponse
from .models import QueryOrderResponse
from .models import CloseUserDataStreamResponse
from .models import KeepaliveUserDataStreamResponse
from .models import StartUserDataStreamResponse


from .models import ModifyOrderSideEnum
from .models import ModifyOrderPriceMatchEnum
from .models import NewOrderSideEnum
from .models import NewOrderTypeEnum
from .models import NewOrderPositionSideEnum
from .models import NewOrderTimeInForceEnum
from .models import NewOrderWorkingTypeEnum
from .models import NewOrderNewOrderRespTypeEnum
from .models import NewOrderPriceMatchEnum
from .models import NewOrderSelfTradePreventionModeEnum

T = TypeVar("T", bound=BaseModel)


class DerivativesTradingCoinFuturesWebSocketAPI(WebSocketAPIBase):
    def __init__(
        self,
        configuration: ConfigurationWebSocketAPI,
    ) -> None:
        super().__init__(configuration)
        self.configuration = configuration
        self.signer = (
            Signers.get_signer(
                configuration.private_key, configuration.private_key_passphrase
            )
            if configuration.private_key is not None
            else None
        )

        self._accountApi = AccountApi(self, self.signer)
        self._tradeApi = TradeApi(self, self.signer)
        self._userDataStreamsApi = UserDataStreamsApi(self, self.signer)

    async def ping_server(self, connection: WebSocketConnection):
        """Sends a ping message to the WebSocket server to check the connection status.

        Args:
            connection (WebSocketConnection): The WebSocket connection to send the ping message to.
        """
        if self.session:
            return await super().ping_ws_api(connection=connection)
        else:
            raise ValueError("WebSocket session is not initialized.")

    async def send_message(
        self,
        payload: Dict,
        promised: bool = True,
        response_model: Type[T] = None,
        api_key: Optional[bool] = False,
        session_logon: Optional[bool] = False,
        session_logout: Optional[bool] = False,
    ) -> WebsocketApiResponse[T]:
        """Sends a message to the WebSocket server.

        Args:
            payload (Dict): The message payload to send.
            promised (bool): Whether the message is promised or not.
            response_model (Type[T]): The expected response model type.
            api_key (Optional[bool]): Whether to include the API key in the request.
            session_logon (Optional[bool]): Whether the message is for session logon.
            session_logout (Optional[bool]): Whether the message is for session logout.
        Returns:
            WebsocketApiResponse[T]: The response from the WebSocket server.
        """

        return await super().send_message(
            payload, promised, response_model, api_key, session_logon, session_logout
        )

    async def send_signed_message(
        self,
        payload: Dict,
        signer: Optional[Signers] = None,
        promised: bool = True,
        response_model: Type[T] = None,
        api_key: Optional[bool] = False,
        session_logon: Optional[bool] = False,
        session_logout: Optional[bool] = False,
    ):
        """Sends a signed message to the WebSocket server.

        Args:
            payload (Dict): The message payload to send.
            signer (Optional[Signers]): The signer to use for signing the message.
            promised (bool): Whether the message is promised or not.
            response_model (Type[T]): The expected response model type.
            api_key (Optional[bool]): Whether to include the API key in the request.
            session_logon (Optional[bool]): Whether the message is for session logon.
            session_logout (Optional[bool]): Whether the message is for session logout.
        Returns:
            WebsocketApiResponse[T]: The response from the WebSocket server.
        """

        return await super().send_signed_message(
            payload,
            signer,
            promised,
            response_model,
            api_key=api_key,
            session_logon=session_logon,
            session_logout=session_logout,
        )

    async def close_connection(
        self, connection: WebSocketConnection = None, close_session: bool = True
    ):
        """Closes the WebSocket connection and optionally the session.

        Args:
            connection (WebSocketConnection, optional): The WebSocket connection to close. If None, the current session's connection is used.
            close_session (bool, optional): Whether to close the session after closing the connection. Defaults to True.
        """

        await super().close_connection(connection, close_session)

    async def account_information(
        self,
        id: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> WebsocketApiResponse[AccountInformationResponse]:
        """
                Account Information(USER_DATA)

                Get current account information. User in single-asset/ multi-assets mode will see different value, see comments in response section for detail.

        Weight: 5

                Args:
                    id (Optional[str] = None): Unique WebSocket request ID.
                    recv_window (Optional[int] = None):

                Returns:
                    WebsocketApiResponse[AccountInformationResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._accountApi.account_information(id, recv_window)

    async def futures_account_balance(
        self,
        id: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> WebsocketApiResponse[FuturesAccountBalanceResponse]:
        """
                Futures Account Balance(USER_DATA)

                Query account balance info

        Weight: 5

                Args:
                    id (Optional[str] = None): Unique WebSocket request ID.
                    recv_window (Optional[int] = None):

                Returns:
                    WebsocketApiResponse[FuturesAccountBalanceResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._accountApi.futures_account_balance(id, recv_window)

    async def cancel_order(
        self,
        symbol: Union[str, None],
        id: Optional[str] = None,
        order_id: Optional[int] = None,
        orig_client_order_id: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> WebsocketApiResponse[CancelOrderResponse]:
        """
                Cancel Order (TRADE)

                Cancel an active order.

        * Either `orderId` or `origClientOrderId` must be sent.

        Weight: 1

                Args:
                    symbol (Union[str, None]):
                    id (Optional[str] = None): Unique WebSocket request ID.
                    order_id (Optional[int] = None):
                    orig_client_order_id (Optional[str] = None):
                    recv_window (Optional[int] = None):

                Returns:
                    WebsocketApiResponse[CancelOrderResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._tradeApi.cancel_order(
            symbol, id, order_id, orig_client_order_id, recv_window
        )

    async def modify_order(
        self,
        symbol: Union[str, None],
        side: Union[ModifyOrderSideEnum, None],
        quantity: Union[float, None],
        price: Union[float, None],
        id: Optional[str] = None,
        order_id: Optional[int] = None,
        orig_client_order_id: Optional[str] = None,
        price_match: Optional[ModifyOrderPriceMatchEnum] = None,
        recv_window: Optional[int] = None,
    ) -> WebsocketApiResponse[ModifyOrderResponse]:
        """
                Modify Order (TRADE)

                Order modify function, currently only LIMIT order modification is supported, modified orders will be reordered in the match queue

        * Either `orderId` or `origClientOrderId` must be sent, and the `orderId` will prevail if both are sent.
        * Both `quantity` and `price` must be sent, which is different from dapi modify order endpoint.
        * When the new `quantity` or `price` doesn't satisfy PRICE_FILTER / PERCENT_FILTER / LOT_SIZE, amendment will be rejected and the order will stay as it is.
        * However the order will be cancelled by the amendment in the following situations:
        * when the order is in partially filled status and the new `quantity` <= `executedQty`
        * When the order is `GTX` and the new price will cause it to be executed immediately
        * One order can only be modfied for less than 10000 times

        Weight: 1 on 10s order rate limit(X-MBX-ORDER-COUNT-10S);
        1 on 1min order rate limit(X-MBX-ORDER-COUNT-1M);
        1 on IP rate limit(x-mbx-used-weight-1m)

                Args:
                    symbol (Union[str, None]):
                    side (Union[ModifyOrderSideEnum, None]): `SELL`, `BUY`
                    quantity (Union[float, None]): Order quantity, cannot be sent with `closePosition=true`
                    price (Union[float, None]):
                    id (Optional[str] = None): Unique WebSocket request ID.
                    order_id (Optional[int] = None):
                    orig_client_order_id (Optional[str] = None):
                    price_match (Optional[ModifyOrderPriceMatchEnum] = None): only available for `LIMIT`/`STOP`/`TAKE_PROFIT` order; can be set to `OPPONENT`/ `OPPONENT_5`/ `OPPONENT_10`/ `OPPONENT_20`: /`QUEUE`/ `QUEUE_5`/ `QUEUE_10`/ `QUEUE_20`; Can't be passed together with `price`
                    recv_window (Optional[int] = None):

                Returns:
                    WebsocketApiResponse[ModifyOrderResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._tradeApi.modify_order(
            symbol,
            side,
            quantity,
            price,
            id,
            order_id,
            orig_client_order_id,
            price_match,
            recv_window,
        )

    async def new_order(
        self,
        symbol: Union[str, None],
        side: Union[NewOrderSideEnum, None],
        type: Union[NewOrderTypeEnum, None],
        id: Optional[str] = None,
        position_side: Optional[NewOrderPositionSideEnum] = None,
        time_in_force: Optional[NewOrderTimeInForceEnum] = None,
        quantity: Optional[float] = None,
        reduce_only: Optional[str] = None,
        price: Optional[float] = None,
        new_client_order_id: Optional[str] = None,
        stop_price: Optional[float] = None,
        close_position: Optional[str] = None,
        activation_price: Optional[float] = None,
        callback_rate: Optional[float] = None,
        working_type: Optional[NewOrderWorkingTypeEnum] = None,
        price_protect: Optional[str] = None,
        new_order_resp_type: Optional[NewOrderNewOrderRespTypeEnum] = None,
        price_match: Optional[NewOrderPriceMatchEnum] = None,
        self_trade_prevention_mode: Optional[
            NewOrderSelfTradePreventionModeEnum
        ] = None,
        recv_window: Optional[int] = None,
    ) -> WebsocketApiResponse[NewOrderResponse]:
        """
                New Order(TRADE)

                Send in a new order.

        * Order with type `STOP`, parameter `timeInForce` can be sent ( default `GTC`).
        * Order with type `TAKE_PROFIT`, parameter `timeInForce` can be sent ( default `GTC`).
        * Condition orders will be triggered when:
        * If parameter `priceProtect` is sent as true:
        * when price reaches the `stopPrice`，the difference rate between "MARK_PRICE" and "CONTRACT_PRICE" cannot be larger than the "triggerProtect" of the symbol
        * "triggerProtect" of a symbol can be got from `GET /dapi/v1/exchangeInfo`
        * `STOP`, `STOP_MARKET`:
        * BUY: latest price ("MARK_PRICE" or "CONTRACT_PRICE") >= `stopPrice`
        * SELL: latest price ("MARK_PRICE" or "CONTRACT_PRICE") <= `stopPrice`
        * `TAKE_PROFIT`, `TAKE_PROFIT_MARKET`:
        * BUY: latest price ("MARK_PRICE" or "CONTRACT_PRICE") <= `stopPrice`
        * SELL: latest price ("MARK_PRICE" or "CONTRACT_PRICE") >= `stopPrice`
        * `TRAILING_STOP_MARKET`:
        * BUY: the lowest price after order placed <= `activationPrice`, and the latest price >= the lowest price * (1 + `callbackRate`)
        * SELL: the highest price after order placed >= `activationPrice`, and the latest price <= the highest price * (1 - `callbackRate`)
        * For `TRAILING_STOP_MARKET`, if you got such error code.
        * BUY: `activationPrice` should be smaller than latest price.
        * SELL: `activationPrice` should be larger than latest price.
        * If `newOrderRespType` is sent as `RESULT`:
        * `MARKET` order: the final FILLED result of the order will be return directly.
        * `LIMIT` order with special `timeInForce`: the final status result of the order(FILLED or EXPIRED) will be returned directly.
        * `STOP_MARKET`, `TAKE_PROFIT_MARKET` with `closePosition=true`:
        * Follow the same rules for condition orders.
        * If triggered，**close all** current long position(if `SELL`) or current short position(if `BUY`).
        * Cannot be used with `quantity` parameter
        * Cannot be used with `reduceOnly` parameter
        * In Hedge Mode, cannot be used with `BUY` orders in `LONG` position side. and cannot be used with `SELL` orders in `SHORT` position side

        Weight: 0

                Args:
                    symbol (Union[str, None]):
                    side (Union[NewOrderSideEnum, None]): `SELL`, `BUY`
                    type (Union[NewOrderTypeEnum, None]): `LIMIT`, `MARKET`, `STOP`, `STOP_MARKET`, `TAKE_PROFIT`, `TAKE_PROFIT_MARKET`, `TRAILING_STOP_MARKET`
                    id (Optional[str] = None): Unique WebSocket request ID.
                    position_side (Optional[NewOrderPositionSideEnum] = None): Default `BOTH` for One-way Mode; `LONG` or `SHORT` for Hedge Mode.  It must be sent in Hedge Mode.
                    time_in_force (Optional[NewOrderTimeInForceEnum] = None):
                    quantity (Optional[float] = None): Quantity measured by contract number, Cannot be sent with `closePosition`=`true`
                    reduce_only (Optional[str] = None): `true` or `false`. default `false`. Cannot be sent in Hedge Mode; cannot be sent with `closePosition`=`true` (Close-All)
                    price (Optional[float] = None):
                    new_client_order_id (Optional[str] = None): A unique id among open orders. Automatically generated if not sent. Can only be string following the rule: `^[.A-Z:/a-z0-9_-]{1,36}$`
                    stop_price (Optional[float] = None): Used with `STOP/STOP_MARKET` or `TAKE_PROFIT/TAKE_PROFIT_MARKET` orders.
                    close_position (Optional[str] = None): `true`, `false`；Close-All，used with `STOP_MARKET` or `TAKE_PROFIT_MARKET`.
                    activation_price (Optional[float] = None): Used with `TRAILING_STOP_MARKET` orders, default as the latest price(supporting different workingType)
                    callback_rate (Optional[float] = None): Used with `TRAILING_STOP_MARKET` orders, min 0.1, max 10 where 1 for 1%
                    working_type (Optional[NewOrderWorkingTypeEnum] = None): stopPrice triggered by: "MARK_PRICE", "CONTRACT_PRICE". Default "CONTRACT_PRICE"
                    price_protect (Optional[str] = None): "TRUE" or "FALSE", default "FALSE". Used with `STOP/STOP_MARKET` or `TAKE_PROFIT/TAKE_PROFIT_MARKET` orders.
                    new_order_resp_type (Optional[NewOrderNewOrderRespTypeEnum] = None): `ACK`,`RESULT`, default `ACK`
                    price_match (Optional[NewOrderPriceMatchEnum] = None): only available for `LIMIT`/`STOP`/`TAKE_PROFIT` order; can be set to `OPPONENT`/ `OPPONENT_5`/ `OPPONENT_10`/ `OPPONENT_20`: /`QUEUE`/ `QUEUE_5`/ `QUEUE_10`/ `QUEUE_20`; Can't be passed together with `price`
                    self_trade_prevention_mode (Optional[NewOrderSelfTradePreventionModeEnum] = None): `NONE`: No STP / `EXPIRE_TAKER`:expire taker order when STP triggers/ `EXPIRE_MAKER`:expire taker order when STP triggers/ `EXPIRE_BOTH`:expire both orders when STP triggers; default `NONE`
                    recv_window (Optional[int] = None):

                Returns:
                    WebsocketApiResponse[NewOrderResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._tradeApi.new_order(
            symbol,
            side,
            type,
            id,
            position_side,
            time_in_force,
            quantity,
            reduce_only,
            price,
            new_client_order_id,
            stop_price,
            close_position,
            activation_price,
            callback_rate,
            working_type,
            price_protect,
            new_order_resp_type,
            price_match,
            self_trade_prevention_mode,
            recv_window,
        )

    async def position_information(
        self,
        id: Optional[str] = None,
        margin_asset: Optional[str] = None,
        pair: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> WebsocketApiResponse[PositionInformationResponse]:
        """
                Position Information(USER_DATA)

                Get current position information.

        * Please use with user data stream `ACCOUNT_UPDATE` to meet your timeliness and accuracy needs.

        Weight: 5

                Args:
                    id (Optional[str] = None): Unique WebSocket request ID.
                    margin_asset (Optional[str] = None):
                    pair (Optional[str] = None):
                    recv_window (Optional[int] = None):

                Returns:
                    WebsocketApiResponse[PositionInformationResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._tradeApi.position_information(
            id, margin_asset, pair, recv_window
        )

    async def query_order(
        self,
        symbol: Union[str, None],
        id: Optional[str] = None,
        order_id: Optional[int] = None,
        orig_client_order_id: Optional[str] = None,
        recv_window: Optional[int] = None,
    ) -> WebsocketApiResponse[QueryOrderResponse]:
        """
                Query Order (USER_DATA)

                Check an order's status.

        * These orders will not be found:
        * order status is `CANCELED` or `EXPIRED` **AND** order has NO filled trade **AND** created time + 3 days < current time
        * order create time + 90 days < current time

        * Either `orderId` or `origClientOrderId` must be sent.
        * `orderId` is self-increment for each specific `symbol`

        Weight: 1

                Args:
                    symbol (Union[str, None]):
                    id (Optional[str] = None): Unique WebSocket request ID.
                    order_id (Optional[int] = None):
                    orig_client_order_id (Optional[str] = None):
                    recv_window (Optional[int] = None):

                Returns:
                    WebsocketApiResponse[QueryOrderResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._tradeApi.query_order(
            symbol, id, order_id, orig_client_order_id, recv_window
        )

    async def close_user_data_stream(
        self,
        id: Optional[str] = None,
    ) -> WebsocketApiResponse[CloseUserDataStreamResponse]:
        """
                Close User Data Stream (USER_STREAM)

                Close out a user data stream.

        Weight: 1

                Args:
                    id (Optional[str] = None): Unique WebSocket request ID.

                Returns:
                    WebsocketApiResponse[CloseUserDataStreamResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._userDataStreamsApi.close_user_data_stream(id)

    async def keepalive_user_data_stream(
        self,
        id: Optional[str] = None,
    ) -> WebsocketApiResponse[KeepaliveUserDataStreamResponse]:
        """
                Keepalive User Data Stream (USER_STREAM)

                Keepalive a user data stream to prevent a time out. User data streams will close after 60 minutes. It's recommended to send a ping about every 60 minutes.

        Weight: 1

                Args:
                    id (Optional[str] = None): Unique WebSocket request ID.

                Returns:
                    WebsocketApiResponse[KeepaliveUserDataStreamResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._userDataStreamsApi.keepalive_user_data_stream(id)

    async def start_user_data_stream(
        self,
        id: Optional[str] = None,
    ) -> WebsocketApiResponse[StartUserDataStreamResponse]:
        """
                Start User Data Stream (USER_STREAM)

                Start a new user data stream. The stream will close after 60 minutes unless a keepalive is sent. If the account has an active `listenKey`, that `listenKey` will be returned and its validity will be extended for 60 minutes.

        Weight: 1

                Args:
                    id (Optional[str] = None): Unique WebSocket request ID.

                Returns:
                    WebsocketApiResponse[StartUserDataStreamResponse]

                Raises:
                    RequiredError: If a required parameter is missing.

        """

        return await self._userDataStreamsApi.start_user_data_stream(id)
