# -*- coding: utf-8 -*-

# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code

from ccxt.async_support.base.exchange import Exchange
from ccxt.abstract.toobit import ImplicitAPI
from ccxt.base.types import Any, Int, Market, Strings, Ticker, Tickers
from typing import List


class toobit(Exchange, ImplicitAPI):

    def describe(self) -> Any:
        return self.deep_extend(super(toobit, self).describe(), {
            'id': 'toobit',
            'name': 'Toobit',
            'countries': ['KY'],  # Cayman Islands
            'rateLimit': 1000,
            'version': '1',
            'certified': False,
            'pro': False,
            'has': {
                'CORS': None,
                'spot': True,
                'margin': False,
                'swap': True,
                'future': False,
                'option': False,
                'addMargin': False,
                'cancelAllOrders': False,
                'cancelOrder': False,
                'cancelOrders': False,
                'createDepositAddress': False,
                'createOrder': False,
                'createStopLimitOrder': False,
                'createStopMarketOrder': False,
                'createStopOrder': False,
                'editOrder': False,
                'fetchBalance': False,
                'fetchBorrowInterest': False,
                'fetchBorrowRateHistories': False,
                'fetchBorrowRateHistory': False,
                'fetchClosedOrders': False,
                'fetchCrossBorrowRate': False,
                'fetchCrossBorrowRates': False,
                'fetchCurrencies': False,
                'fetchDepositAddress': False,
                'fetchDeposits': False,
                'fetchFundingHistory': False,
                'fetchFundingRate': False,
                'fetchFundingRateHistory': False,
                'fetchFundingRates': False,
                'fetchIndexOHLCV': False,
                'fetchIsolatedBorrowRate': False,
                'fetchIsolatedBorrowRates': False,
                'fetchL2OrderBook': False,
                'fetchLedger': False,
                'fetchLedgerEntry': False,
                'fetchLeverageTiers': False,
                'fetchMarkets': True,
                'fetchMarkOHLCV': False,
                'fetchMyTrades': False,
                'fetchOHLCV': True,
                'fetchOpenInterestHistory': False,
                'fetchOpenOrders': False,
                'fetchOrder': False,
                'fetchOrderBook': True,
                'fetchOrders': False,
                'fetchOrderTrades': 'emulated',
                'fetchPositions': False,
                'fetchPremiumIndexOHLCV': False,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': False,
                'fetchTrades': False,
                'fetchTradingFee': False,
                'fetchTradingFees': False,
                'fetchWithdrawals': False,
                'setLeverage': False,
                'setMarginMode': False,
                'transfer': False,
                'withdraw': False,
            },
            'comment': 'This comment is optional',
            'urls': {
                'logo': 'https://toobit-docs.github.io/apidocs/spot/v1/en/images/logo.svg',
                'api': {
                    'public': 'https://api.toobit.com',
                },
                'www': 'https://www.toobit.com/',
                'doc': [
                    'https://toobit-docs.github.io/apidocs/spot/v1/en/#change-log',
                ],
            },
            'timeframes': {
                '1m': '1m',
                '3m': '3m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '2h': '2h',
                '4h': '4h',
                '6h': '6h',
                '12h': '12h',
                '1d': '1d',
                '1w': '1w',
                '1M': '1M',
            },
            'api': {
                'public': {
                    'get': {
                        'quote/v1/ticker/24hr': 1,
                        'quote/v1/klines': 1,
                        '/api/v1/exchangeInfo': 1,
                    },
                },
            },
            'fees': {
                'trading': {
                    'tierBased': False,
                    'percentage': True,
                    'maker': self.parse_number('0.001'),
                    'taker': self.parse_number('0.001'),
                },
            },
        })

    async def fetch_markets(self, params={}) -> List[Market]:
        """
        retrieves data on all markets for toobit
        https://api.toobit.com/api/v1/exchangeInfo
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        response = await self.publicGetApiV1ExchangeInfo()
        symbols = self.safe_value(response, 'symbols', [])
        result = []
        for i in range(0, len(symbols)):
            symbolData = symbols[i]
            status = self.safe_value(symbolData, 'status')
            symbol = self.safe_value(symbolData, 'symbol')
            if status != 'TRADING' or symbol == 'TESTA1S3TESTX8Z9':
                continue
            market = self.parse_market(symbolData)
            result.append(market)
        return result

    def parse_market(self, market) -> Market:
        #         {
        #             "filters": [
        #                 {
        #                     "minPrice": "0.01",
        #                     "maxPrice": "10000000.00000000",
        #                     "tickSize": "0.01",
        #                     "filterType": "PRICE_FILTER"
        #                 },
        #                 {
        #                     "minQty": "0.0001",
        #                     "maxQty": "4000",
        #                     "stepSize": "0.0001",
        #                     "filterType": "LOT_SIZE"
        #                 },
        #                 {
        #                     "minNotional": "5",
        #                     "filterType": "MIN_NOTIONAL"
        #                 }
        #             ],
        #             "exchangeId": "301",
        #             "symbol": "ETHUSDT",
        #             "symbolName": "ETHUSDT",
        #             "status": "TRADING",
        #             "baseAsset": "ETH",
        #             "baseAssetName": "ETH",
        #             "baseAssetPrecision": "0.0001",
        #             "quoteAsset": "USDT",
        #             "quoteAssetName": "USDT",
        #             "quotePrecision": "0.01",
        #             "icebergAllowed": False,
        #             "isAggregate": False,
        #             "allowMargin": True
        #         }
        symbol = self.safe_value(market, 'symbol')
        baseAsset = self.safe_value(market, 'baseAsset')
        quoteAsset = self.safe_value(market, 'quoteAsset')
        baseAssetPrecision = self.safe_value(market, 'baseAssetPrecision')
        quotePrecision = self.safe_value(market, 'quotePrecision')
        allowMargin = self.safe_value(market, 'allowMargin', False)
        filters = self.safe_value(market, 'filters', [])
        # Parse filters to extract limits and precision
        minPrice = None
        maxPrice = None
        tickSize = None
        minQty = None
        maxQty = None
        stepSize = None
        minNotional = None
        minAmount = None
        maxAmount = None
        for i in range(0, len(filters)):
            filter = filters[i]
            filterType = self.safe_value(filter, 'filterType')
            if filterType == 'PRICE_FILTER':
                minPrice = self.safe_number(filter, 'minPrice')
                maxPrice = self.safe_number(filter, 'maxPrice')
                tickSize = self.safe_string(filter, 'tickSize')
            elif filterType == 'LOT_SIZE':
                minQty = self.safe_number(filter, 'minQty')
                maxQty = self.safe_number(filter, 'maxQty')
                stepSize = self.safe_string(filter, 'stepSize')
            elif filterType == 'MIN_NOTIONAL':
                minNotional = self.safe_number(filter, 'minNotional')
            elif filterType == 'TRADE_AMOUNT':
                minAmount = self.safe_number(filter, 'minAmount')
                maxAmount = self.safe_number(filter, 'maxAmount')
        id = symbol
        base = self.safe_currency_code(baseAsset)
        quote = self.safe_currency_code(quoteAsset)
        baseId = baseAsset.lower()
        quoteId = quoteAsset.lower()
        # Calculate precision from step sizes and precision strings
        amountPrecision = str(self.precision_from_string(stepSize)) if stepSize else self.precision_from_string(baseAssetPrecision)
        pricePrecision = str(self.precision_from_string(tickSize)) if tickSize else self.precision_from_string(quotePrecision)
        return {
            'id': id,
            'symbol': base + '/' + quote,
            'base': base,
            'quote': quote,
            'settle': None,
            'baseId': baseId,
            'quoteId': quoteId,
            'settleId': None,
            'type': 'spot',
            'spot': True,
            'margin': allowMargin,
            'swap': False,
            'future': False,
            'option': False,
            'active': True,
            'contract': False,
            'linear': None,
            'inverse': None,
            'contractSize': None,
            'expiry': None,
            'expiryDatetime': None,
            'strike': None,
            'optionType': None,
            'precision': {
                'amount': amountPrecision,
                'price': pricePrecision,
            },
            'limits': {
                'leverage': {
                    'min': None,
                    'max': None,
                },
                'amount': {
                    'min': minQty,
                    'max': maxQty,
                },
                'price': {
                    'min': minPrice,
                    'max': maxPrice,
                },
                'cost': {
                    'min': minNotional or minAmount,
                    'max': maxAmount,
                },
            },
            'created': None,
            'info': market,
        }

    async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
        """
        fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
        https://toobit-docs.github.io/apidocs/spot/v1/en/#tickers
        :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
        """
        await self.load_markets()
        if symbols is not None:
            symbols = self.market_symbols(symbols)
        response = await self.publicGetQuoteV1Ticker24hr()
        result = {}
        for i in range(0, len(response)):
            volume = self.safe_float(response[i], 'v')
            if volume == 0:
                continue
            ticker = self.parse_ticker(response[i])
            symbol = ticker['symbol']
            result[symbol] = ticker
        return self.filter_by_array_tickers(result, 'symbol', symbols)

    async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        https://toobit-docs.github.io/apidocs/spot/v1/en/#ticker
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'symbol': market['id'],
        }
        response = await self.publicGetQuoteV1Ticker24hr(request)
        ticker = self.parse_ticker(response[0])
        return ticker

    def parse_ticker(self, ticker, market: Market = None) -> Ticker:
        #         {
        # t: 1757164008834,
        # s: "BTCUSDT",
        # c: "110895.06",
        # h: "113310.01",
        # l: "110219.01",
        # o: "112951.99",
        # v: "3893.406649",
        # qv: "433374169.27969515",
        # pc: "-2056.93",
        # pcp: "-0.0182"
        # }
        marketType = 'spot'
        symbol = self.safe_value(ticker, 's')
        marketId = symbol
        symbol = self.safe_symbol(marketId, market, None, marketType)
        high = self.safe_float(ticker, 'h')
        low = self.safe_float(ticker, 'l')
        open = self.safe_float(ticker, 'o')
        close = self.safe_float(ticker, 'c')
        last = self.safe_float(ticker, 'c')
        change = self.safe_float(ticker, 'pcp')
        priceChange = self.safe_float(ticker, 'pc')
        baseVolume = self.safe_float(ticker, 'v')
        quoteVolume = self.safe_float(ticker, 'qv')
        datetime = self.safe_string(ticker, 't')
        bid = self.safe_float(ticker, 'b', 0)
        ask = self.safe_float(ticker, 'a', 0)
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': datetime,
            'datetime': self.parse8601(datetime),
            'high': high,
            'low': low,
            'bid': bid,
            'bidVolume': None,
            'ask': ask,
            'askVolume': None,
            'vwap': None,
            'open': open,
            'close': close,
            'last': last,
            'previousClose': None,
            'change': priceChange,
            'percentage': change,
            'average': None,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        }, market)

    async def fetch_ohlcv(self, symbol: str, timeframe='1h', since: Int = None, limit: Int = None, params={}) -> List[list]:
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        https://toobit-docs.github.io/apidocs/spot/v1/en/#chart
        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: the maximum amount of candles to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        await self.load_markets()
        market = self.market(symbol)
        endTime = Date.now()
        request = {
            'symbol': market['id'],
            'from': (endTime - (24 * 60 * 60 * 1000)),
            'to': endTime,
            'interval': self.safe_string(self.timeframes, timeframe, timeframe),
        }
        if since is not None:
            request['from'] = since
        if timeframe is not None:
            request['interval'] = self.safe_string(self.timeframes, timeframe, timeframe)
        response = await self.publicGetQuoteV1Klines(request)
        ohlcvs = []
        for i in range(0, len(response)):
            candle = response[i]
            ts = self.safe_timestamp(candle, 0)
            open = self.safe_float(candle, 1)
            high = self.safe_float(candle, 2)
            low = self.safe_float(candle, 3)
            close = self.safe_float(candle, 4)
            volume = self.safe_float(candle, 5)
            ohlcvs.append([
                ts,
                open,
                high,
                low,
                close,
                volume,
            ])
        return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        query = self.omit(params, self.extract_params(path))
        url = self.urls['api']['public'] + '/' + path
        if path == 'quote/v1/ticker/24hr':
            url = url + '?' + self.urlencode(query)
        if path == 'quote/v1/klines':
            url = url + '?' + self.urlencode(query)
        headers = {'Content-Type': 'application/json'}
        return {'url': url, 'method': method, 'body': body, 'headers': headers}
