"""

CCXT client


"""

import ccxt
from loguru import logger

from ._client import CexClient


class CcxtHandler(CexClient):
    """
    Library: https://github.com/ccxt/ccxt

    Args:
        None

    Returns:
        None

    """

    def __init__(
        self,
        **kwargs,
    ):
        """
        Initialize the client

        """
        super().__init__(**kwargs)
        if self.name is None:
            return
        client = getattr(ccxt, self.name)
        self.balance_limit = kwargs.get("balance_limit", True)
        self.balance_limit_value = kwargs.get("balance_limit_value", 5)
        self.client = client(
            {
                "apiKey": self.api_key,
                "secret": self.secret,
                "password": self.password,
                "enableRateLimit": True,
                "options": {
                    "defaultType": self.defaulttype,
                },
            }
        )
        if self.testmode:
            self.client.set_sandbox_mode("enabled")
        self.account_number = self.client.uid
        self.name = self.client.id

    async def get_quote(self, instrument):
        """
        Asynchronously fetches a ask/offer quote
        for the specified instrument.

        :param instrument: The instrument for which the quote is to be fetched.
        :return: The fetched quote.
        """
        try:
            instrument = await self.replace_instrument(instrument)
            quote = self.client.fetch_ticker(instrument)["ask"]
            logger.debug("Quote: {}", quote)
            return quote
        except Exception as e:
            logger.error("{} Error {}", self.name, e)

    async def get_bid(self, instrument):
        """
        Asynchronously retrieves the bid
        for the specified instrument.

        Args:
            instrument: The instrument for which
            the bid is to be retrieved.

        Returns:
            The bid for the specified instrument.
        """
        try:
            instrument = await self.replace_instrument(instrument)
            return await self.client.fetch_ticker(instrument)["bid"]
        except Exception as e:
            logger.error("{} Error {}", self.name, e)

    async def get_account_balance(self):
        """
        return account balance of
        a given ccxt exchange

        Args:
            None

        Returns:
            balance

        """
        try:
            raw_balance = self.client.fetch_free_balance()
            data = list(raw_balance.items())
            if self.balance_limit:
                data = data[: self.balance_limit_value]
            if filtered_balance := {k: v for k, v in data if v is not None and v > 0}:
                balance_str = "".join(
                    f"{iterator}: {value} \n"
                    for iterator, value in filtered_balance.items()
                )
                return f"{balance_str}"
        except Exception as e:
            logger.error("{} get_account_balance {}", self.name, e)
            return e

    async def get_account_position(self):
        """
        Return account position.
        of a given exchange

        Args:
            None

        Returns:
            position

        """

        try:
            positions = self.client.fetch_positions()
            if positions := [p for p in positions if p["type"] == "open"]:
                return f"{positions}"
        except Exception as e:
            logger.error("{} Error {}", self.name, e)
            return e

    async def pre_order_checks(self, order_params):
        """ """
        return True

    async def get_trading_asset_balance(self):
        """ """
        return self.client.fetchBalance()[f"{self.trading_asset}"]["free"]

    async def execute_order(self, order_params):
        """
        Execute order

        Args:
            order_params (dict):
                action(str)
                instrument(str)
                quantity(int)

        Returns:
            trade_confirmation(dict)

        """
        try:
            action = order_params["action"]
            instrument = await self.replace_instrument(order_params["instrument"])
            quantity = order_params.get("quantity", self.trading_risk_amount)
            amount = await self.get_order_amount(
                quantity=quantity,
                instrument=instrument,
                is_percentage=self.trading_risk_percentage,
            )
            params = {
                "stopLoss": {"triggerPrice": order_params.get("stop_loss")},
                "takeProfit": {"triggerPrice": order_params.get("take_profit")},
            }
            if amount and await self.pre_order_checks(order_params):
                order = self.client.create_order(
                    symbol=instrument,
                    type=self.ordertype,
                    side=action,
                    amount=amount,
                    params=params,
                )
                return await self.get_trade_confirmation(order, instrument, action)
            return f"Error executing {self.name}"
        except Exception as e:
            logger.error("{} Error {}", self.name, e)
            return f"Error executing {self.name}"

    # async def execute_order(self, order_params):
    #     """
    #     Execute order

    #     Args:
    #         order_params (dict):
    #             action(str)
    #             instrument(str)
    #             quantity(int)

    #     Returns:
    #         trade_confirmation(dict)

    #     """
    #     try:
    #         action = order_params.get("action")
    #         instrument = await self.replace_instrument(order_params.get("instrument"))
    #         quantity = order_params.get("quantity", self.trading_risk_amount)
    #         logger.debug("quantity {}", quantity)
    #         amount = await self.get_order_amount(
    #             quantity=quantity,
    #             instrument=instrument,
    #             is_percentage=self.trading_risk_percentage,
    #         )
    #         params = {
    #             "stopLoss": {
    #                 "triggerPrice": order_params.get("stop_loss"),
    #                 # "price": order_params.get("action") * 0.98,
    #             },
    #             "takeProfit": {
    #                 "triggerPrice": order_params.get("take_profit"),
    #                 # "price": order_params.get("action") * 0.98,
    #             },
    #         }
    #         logger.debug("amount {}", amount)
    #         pre_order_checks = await self.pre_order_checks(order_params)
    #         logger.debug("pre_order_checks {}", pre_order_checks)

    #         if amount and pre_order_checks:
    #             if order := self.client.create_order(
    #                 symbol=instrument,
    #                 type=self.ordertype,
    #                 side=action,
    #                 amount=amount,
    #                 params=params,
    #             ):
    #                 return await self.get_trade_confirmation(
    # order, instrument, action)
    #         return f"Error executing {self.name}"

    #     except Exception as e:
    #         logger.error("{} Error {}", self.name, e)
    #         return f"Error executing {self.name}"
