# Copyright 2020 Polo Digital Assets, Ltd.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE

from uuid import uuid4

from polofutures.rest.core import SendRequest


class TradeClient:
    def __init__(self, key=None, secret=None, passphrase=None, base_url=None):
        self._request = SendRequest(key, secret, passphrase, base_url)

    def get_fund_history(self, symbol, **kwargs):
        """
        Submit request to get the funding history.

        Param	    Type	Description
        symbol	    String	Symbol of the contract
        startAt	    long	[optional] Start time (milisecond)
        endAt	    long	[optional] End time (milisecond)
        reverse	    boolean	[optional] This parameter functions to judge whether the lookup is forward or not. True means “yes” and False means “no”. This parameter is set as true by default
        offset	    long	[optional] Start offset. The unique attribute of the last returned result of the last request. The data of the first page will be returned by default.
        forward	    boolean	[optional] This parameter functions to judge whether the lookup is forward or not. True means “yes” and False means “no”. This parameter is set as true by default
        maxCount	int	    [optional] Max record count. The default record count is 10"""

        params = {
            'symbol': symbol
        }
        params.update(kwargs)

        return self._request('GET', '/api/v1/funding-history', params, True)

    def get_position_details(self, symbol):
        """
        Get the position details of a specified position."""

        params = {
            'symbol': symbol
        }

        return self._request('GET', '/api/v1/position', params, True)

    def get_all_positions(self):
        """
        Get the position details of a specified position."""

        return self._request('GET', '/api/v1/positions', auth=True)

    def modify_auto_deposit_margin(self, symbol, status=True):
        """
        Enable/Disable of Auto-Deposit Margin"""

        params = {
            'symbol': symbol,
            'status': status
        }

        return self._request('POST', '/api/v1/position/margin/auto-deposit-status', params, True)

    def add_margin_manually(self, symbol, margin, biz_no):
        """
        Add Margin Manually

        Param	Type	    Description
        symbol	String	    Ticker symbol of the contract
        margin	BigDecimal	Margin amount (min. margin amount≥0.00001667XBT）
        biz_no	String	    A unique ID generated by the user, to ensure the operation is processed by the system only once"""

        params = {
            'symbol': symbol,
            'margin': margin,
            'bizNo' : biz_no
        }

        return self._request('POST', '/api/v1/position/margin/deposit-margin', params, True)

    def get_fills_details(self, symbol, **kwargs):
        """
        Get a list of recent fills.

        Param	Type	Description
        orderId	String	[optional] List fills for a specific order only (If you specify orderId, other parameters can be ignored)
        symbol	String	[optional] Symbol of the contract
        side	String	[optional] buy or sell
        type	String	[optional] limit, market, limit_stop or market_stop
        startAt	long	[optional] Start time (milisecond)
        endAt	long	[optional] End time (milisecond)"""

        params = {
            'symbol': symbol
        }
        params.update(kwargs)

        return self._request('GET', '/api/v1/fills', params, True)

    def get_recent_fills(self):
        """
        Get a list of recent 1000 fills in the last 24 hours. If you need to get your recent traded order history with low latency, you may query this endpoint."""

        return self._request('GET', '/api/v1/recentFills', auth=True)

    def get_open_order_details(self, symbol):
        """
        You can query this endpoint to get the the total number and value of the all your active orders."""

        params = {
            'symbol': symbol
        }

        return self._request('GET', '/api/v1/openOrderStatistics', params, True)

    def create_limit_order(self, symbol, side, leverage, size, price, client_oid=None, **kwargs):
        """
        You can place two types of orders: limit and market. Orders can only be placed if your account has sufficient funds.
        Once an order is placed, your funds will be put on hold for the duration of the order. The amount of funds on hold depends on the order type and parameters specified.
        Please be noted that the system would hold the fees from the orders entered the orderbook in advance.
        Read Get Fills to learn more.

        Do NOT include extra spaces in JSON strings.
        The maximum limit orders for a single contract is 100 per account, and the maximum stop orders for a single contract is 50 per account.

        Param	    type	Description
        clientOid	String	Unique order id created by users to identify their orders, e.g. UUID, Only allows numbers, characters, underline(_), and separator(-)
        side	    String	buy or sell
        symbol	    String	a valid contract code. e.g. XBTUSDM
        type	    String	[optional] Either limit or market
        leverage	String	Leverage of the order
        remark  	String	[optional] remark for the order, length cannot exceed 100 utf8 characters
        stop    	String	[optional] Either down or up. Requires stopPrice and stopPriceType to be defined
        stopPrice   Type	String	[optional] Either TP, IP or MP, Need to be defined if stop is specified.
        stopPrice	String	[optional] Need to be defined if stop is specified.
        reduceOnly	boolean	[optional] A mark to reduce the position size only. Set to false by default.
        closeOrder	boolean	[optional] A mark to close the position. Set to false by default.
        forceHold	boolean	[optional] A mark to forcely hold the funds for an order, even though it's an order to reduce the position size. This helps the order stay on the order book and not get canceled when the position size changes. Set to false by default.

        Advanced Order Details:

        Param	    type	Description
        price	    String	Limit price
        size	    Integer	Order size. Must be a positive number
        timeInForce	String	[optional] GTC, IOC(default is GTC), read Time In Force
        postOnly	boolean	[optional] Post only flag, invalid when timeInForce is IOC. When postOnly chose, not allowed choose hidden or iceberg.
        hidden  	boolean	[optional] Orders not displaying in order book. When hidden chose, not allowed choose postOnly.
        iceberg	    boolean	[optional] Only visible portion of the order is displayed in the order book. When iceberg chose, not allowed choose postOnly.
        visibleSize	Integer	[optional] The maximum visible size of an iceberg order"""

        client_oid = str(client_oid) if client_oid else str(uuid4())

        params = {
            'symbol'   : symbol,
            'size'     : size,
            'side'     : side,
            'price'    : price,
            'leverage' : leverage,
            'clientOid': client_oid
        }

        if kwargs:
            params.update(kwargs)

        return self._request('POST', '/api/v1/orders', params, True)

    def create_market_order(self, symbol, side, leverage, client_oid=None, **kwargs):
        """
        Place Market Order Functions

        Param	type	Description
        size	Integer	[optional] amount of contract to buy or sell"""

        client_oid = str(client_oid) if client_oid else str(uuid4())

        params = {
            'symbol'   : symbol,
            'side'     : side,
            'leverage' : leverage,
            'clientOid': client_oid
        }

        if kwargs:
            params.update(kwargs)

        return self._request('POST', '/api/v1/orders', params, True)

    def cancel_order(self, order_id):
        """
        Cancel an order (including a stop order).

        You will receive success message once the system has received the cancellation request.
        The cancellation request will be processed by matching engine in sequence.
        To know if the request has been processed, you may check the order status or update message from the pushes.
        The order id is the server-assigned order id，not the specified clientOid.
        If the order can not be canceled (already filled or previously canceled, etc), then an error response will indicate the reason in the message field."""

        return self._request('DELETE', f'/api/v1/orders/{order_id}', auth=True)

    def cancel_all_limit_orders(self, symbol):
        """
        Cancel all open orders (excluding stop orders). The response is a list of orderIDs of the canceled orders."""

        params = {
            'symbol': symbol
        }

        return self._request('DELETE', '/api/v1/orders', params, True)

    def cancel_all_stop_orders(self, symbol):
        """
        Cancel all untriggered stop orders. The response is a list of orderIDs of the canceled stop orders.
        To cancel triggered stop orders, please use 'Limit Order Mass Cancelation'."""

        params = {
            'symbol': symbol
        }

        return self._request('DELETE', '/api/v1/stopOrders', params, True)

    def get_order_list(self, **kwargs):
        """
        List your current orders.

        Param	Type	Description
        status	String	[optional] active or done, done as default. Only list orders for a specific status
        symbol	String	[optional] Symbol of the contract
        side	String	[optional] buy or sell
        type	String	[optional] limit, market, limit_stop or market_stop
        startAt	long	[optional] Start time (milisecond)
        endAt	long	[optional] End time (milisecond)"""

        return self._request('GET', '/api/v1/orders', kwargs, True)

    def get_open_stop_orders(self, **kwargs):
        """
        Get the un-triggered stop orders list.

        Param	Type	Description
        symbol	String	[optional] Symbol of the contract
        side	String	[optional] buy or sell
        type	String	[optional] limit, market
        startAt	long	[optional] Start time (milisecond)
        endAt	long	[optional] End time (milisecond)"""

        return self._request('GET', '/api/v1/stopOrders', kwargs, True)

    def get_24h_done_orders(self):
        """
        Get a list of recent 1000 orders in the last 24 hours.
        If you need to get your recent traded order history with low latency, you may query this endpoint."""

        return self._request('GET', '/api/v1/recentDoneOrders', auth=True)

    def get_order_details(self, order_id):
        """
        Get a single order by order id (including a stop order).

        Param	Type	Description
        order_id	String	Order ID"""

        return self._request('GET', f'/api/v1/orders/{order_id}', auth=True)
