import treq

from typing import Dict
from ice3x.clients.abc import IceCubedClientBase
from ice3x.decorators import add_nonce, requires_authentication
from twisted.internet.defer import Deferred
from twisted.internet.defer import inlineCallbacks


class IceCubedAsyncClient(IceCubedClientBase):
    @inlineCallbacks
    def _fetch_resource(self, method: str, suffix: str, params: Dict = {}) -> Deferred:
        headers = {"User-Agent": "Mozilla/4.0 (compatible; Ice3x Async Python client)"}

        if method == "post":
            headers.update({"Key": self.api_key, "Sign": self.sign(params)})

        kwargs = {"params": params, "headers": headers}

        url = f"{self.BASE_URI}{suffix}"
        resp = yield treq.request(method, url, **kwargs)
        data = yield resp.json()
        return data

    def __init__(self, api_key: str = None, secret: str = None) -> None:
        """Instantiate the client

        Args:
            api_key: An ICE3X public API key
            secret: An ICE3X private API key
        """
        self.api_key = api_key
        self.secret = secret

    def get_public_trade_info(self, trade_id: int, **params: Dict) -> Deferred:
        """Fetch public info relating to a specified trade

        Args:
            trade_id: A valid trade id

        Returns:
            Data relating to the specified trade id
        """
        params.update({"trade_id": trade_id})
        return self._fetch_resource("get", "trade/info", params)

    def get_public_trade_list(self, **params: Dict) -> Deferred:
        """Fetch a public facing list of trades

        Returns:
            A list of public trade data
        """
        return self._fetch_resource("get", "trade/list", params)

    def get_market_depth(self, **params: Dict) -> Deferred:
        """Fetch the public market depth

        Returns:
            A market depth data
        """
        return self._fetch_resource("get", "stats/marketdepth", params)

    def get_pair_info(self, pair_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"pair_id": pair_id})
        return self._fetch_resource("get", "pair/info", params)

    def get_pair_list(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("get", "pair/list", params)

    def get_currency_info(self, currency_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"currency_id": currency_id})
        return self._fetch_resource("get", "currency/info", params)

    def get_currency_list(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("get", "currency/list", params)

    def get_orderbook_info(self, pair_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"pair_id": pair_id})
        return self._fetch_resource("get", "orderbook/info", params)

    def get_market_depth_full(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("get", "stats/marketdepthfull", params)

    def get_market_depth_bt_cav(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("get", "stats/marketdepthbtcav", params)

    @add_nonce
    @requires_authentication
    def get_invoice_list(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("post", "invoice/list", params)

    @add_nonce
    @requires_authentication
    def get_invoice_info(self, invoice_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"invoice_id": invoice_id})
        return self._fetch_resource("post", "invoice/info", params)

    @add_nonce
    @requires_authentication
    def get_invoice_pdf(self, invoice_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"invoice_id": invoice_id})
        return self._fetch_resource("post", "invoice/pdf", params)

    @add_nonce
    @requires_authentication
    def cancel_order(self, order_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"order_id": order_id})
        return self._fetch_resource("post", "order/cancel", params)

    @add_nonce
    @requires_authentication
    def create_order(
        self, pair_id: int, kind: str, price: float, amount: float, **params: Dict
    ) -> Deferred:
        """Creates a new order given the provided inputs

        Args:
            paid_id: Currency pair id
            kind: Transaction type i.e. 'buy' or 'sell'
            price: The price to be transacted at
            volume: The volume to be transacted
        """
        params.update(
            {"pair_id": pair_id, "amount": amount, "price": price, "type": kind}
        )

        return self._fetch_resource("post", "order/new", params)

    @add_nonce
    @requires_authentication
    def get_order_info(self, order_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"order_id": order_id})
        return self._fetch_resource("post", "order/info", params)

    @add_nonce
    @requires_authentication
    def get_order_list(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("post", "order/list", params)

    @add_nonce
    @requires_authentication
    def get_transaction_info(self, transaction_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"transaction_id": transaction_id})
        return self._fetch_resource("post", "transaction/info", params)

    @add_nonce
    @requires_authentication
    def get_transaction_list(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("post", "transaction/list", params)

    @add_nonce
    @requires_authentication
    def get_trade_info(self, trade_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"trade_id": trade_id})
        return self._fetch_resource("post", "trade/info", params)

    @add_nonce
    @requires_authentication
    def get_trade_list(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("post", "trade/list", params)

    @add_nonce
    @requires_authentication
    def get_balance_list(self, **params: Dict) -> Deferred:
        """"""
        return self._fetch_resource("post", "balance/list", params)

    @add_nonce
    @requires_authentication
    def get_balance_info(self, currency_id: int, **params: Dict) -> Deferred:
        """"""
        params.update({"currency_id": currency_id})
        return self._fetch_resource("post", "balance/info", params)
