# -*- 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.pro.base.exchange import Exchange
import ccxt.async_support
from ccxt.pro.base.cache import ArrayCache
from ccxt.base.errors import ExchangeError


class zb(Exchange, ccxt.async_support.zb):

    def describe(self):
        return self.deep_extend(super(zb, self).describe(), {
            'has': {
                'ws': True,
                'watchOrderBook': True,
                'watchTicker': True,
                'watchTrades': True,
            },
            'urls': {
                'api': {
                    'ws': 'wss://api.{hostname}/websocket',
                },
            },
            'options': {
                'tradesLimit': 1000,
                'ordersLimit': 1000,
                'OHLCVLimit': 1000,
            },
        })

    async def watch_public(self, name, symbol, method, params={}):
        await self.load_markets()
        market = self.market(symbol)
        symbol = market['symbol']
        messageHash = market['baseId'] + market['quoteId'] + '_' + name
        url = self.implode_hostname(self.urls['api']['ws'])
        request = {
            'event': 'addChannel',
            'channel': messageHash,
        }
        message = self.extend(request, params)
        subscription = {
            'name': name,
            'symbol': symbol,
            'marketId': market['id'],
            'messageHash': messageHash,
            'method': method,
        }
        return await self.watch(url, messageHash, message, messageHash, subscription)

    async def watch_ticker(self, symbol, params={}):
        """
        watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict params: extra parameters specific to the zb api endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/en/latest/manual.html#ticker-structure>`
        """
        return await self.watch_public('ticker', symbol, self.handle_ticker, params)

    def handle_ticker(self, client, message, subscription):
        #
        #     {
        #         date: '1624398991255',
        #         ticker: {
        #             high: '33298.38',
        #             vol: '56375.9469',
        #             last: '32396.95',
        #             low: '28808.19',
        #             buy: '32395.81',
        #             sell: '32409.3',
        #             turnover: '1771122527.0000',
        #             open: '31652.44',
        #             riseRate: '2.36'
        #         },
        #         dataType: 'ticker',
        #         channel: 'btcusdt_ticker'
        #     }
        #
        symbol = self.safe_string(subscription, 'symbol')
        channel = self.safe_string(message, 'channel')
        market = self.market(symbol)
        data = self.safe_value(message, 'ticker')
        data['date'] = self.safe_value(message, 'date')
        ticker = self.parse_ticker(data, market)
        ticker['symbol'] = symbol
        self.tickers[symbol] = ticker
        client.resolve(ticker, channel)
        return message

    async def watch_trades(self, symbol, since=None, limit=None, params={}):
        """
        get the list of most recent trades for a particular symbol
        :param str symbol: unified symbol of the market to fetch trades for
        :param int|None since: timestamp in ms of the earliest trade to fetch
        :param int|None limit: the maximum amount of trades to fetch
        :param dict params: extra parameters specific to the zb api endpoint
        :returns [dict]: a list of `trade structures <https://docs.ccxt.com/en/latest/manual.html?#public-trades>`
        """
        await self.load_markets()
        symbol = self.symbol(symbol)
        trades = await self.watch_public('trades', symbol, self.handle_trades, params)
        if self.newUpdates:
            limit = trades.getLimit(symbol, limit)
        return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)

    def handle_trades(self, client, message, subscription):
        #
        #     {
        #         data: [
        #             {date: 1624537147, amount: '0.0357', price: '34066.11', trade_type: 'bid', type: 'buy', tid: 1718857158},
        #             {date: 1624537147, amount: '0.0255', price: '34071.04', trade_type: 'bid', type: 'buy', tid: 1718857159},
        #             {date: 1624537147, amount: '0.0153', price: '34071.29', trade_type: 'bid', type: 'buy', tid: 1718857160}
        #         ],
        #         dataType: 'trades',
        #         channel: 'btcusdt_trades'
        #     }
        #
        channel = self.safe_value(message, 'channel')
        symbol = self.safe_string(subscription, 'symbol')
        market = self.market(symbol)
        data = self.safe_value(message, 'data')
        trades = self.parse_trades(data, market)
        tradesArray = self.safe_value(self.trades, symbol)
        if tradesArray is None:
            limit = self.safe_integer(self.options, 'tradesLimit', 1000)
            tradesArray = ArrayCache(limit)
        for i in range(0, len(trades)):
            tradesArray.append(trades[i])
        self.trades[symbol] = tradesArray
        client.resolve(tradesArray, channel)

    async def watch_order_book(self, symbol, limit=None, params={}):
        """
        watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int|None limit: the maximum amount of order book entries to return
        :param dict params: extra parameters specific to the zb api endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/en/latest/manual.html#order-book-structure>` indexed by market symbols
        """
        if limit is not None:
            if (limit != 5) and (limit != 10) and (limit != 20):
                raise ExchangeError(self.id + ' watchOrderBook limit argument must be None, 5, 10 or 20')
        else:
            limit = 5  # default
        await self.load_markets()
        market = self.market(symbol)
        symbol = market['symbol']
        name = 'quick_depth'
        messageHash = market['baseId'] + market['quoteId'] + '_' + name
        url = self.implode_hostname(self.urls['api']['ws']) + '/' + market['baseId']
        request = {
            'event': 'addChannel',
            'channel': messageHash,
            'length': limit,
        }
        message = self.extend(request, params)
        subscription = {
            'name': name,
            'symbol': symbol,
            'marketId': market['id'],
            'messageHash': messageHash,
            'method': self.handle_order_book,
        }
        orderbook = await self.watch(url, messageHash, message, messageHash, subscription)
        return orderbook.limit()

    def handle_order_book(self, client, message, subscription):
        #
        #     {
        #         lastTime: 1624524640066,
        #         dataType: 'quickDepth',
        #         channel: 'btcusdt_quick_depth',
        #         currentPrice: 33183.79,
        #         listDown: [
        #             [33166.87, 0.2331],
        #             [33166.86, 0.15],
        #             [33166.76, 0.15],
        #             [33161.02, 0.212],
        #             [33146.35, 0.6066]
        #         ],
        #         market: 'btcusdt',
        #         listUp: [
        #             [33186.88, 0.15],
        #             [33190.1, 0.15],
        #             [33193.03, 0.2518],
        #             [33195.05, 0.2031],
        #             [33199.99, 0.6066]
        #         ],
        #         high: 34816.8,
        #         rate: '6.484',
        #         low: 32312.41,
        #         currentIsBuy: True,
        #         dayNumber: 26988.5536,
        #         totalBtc: 26988.5536,
        #         showMarket: 'btcusdt'
        #     }
        #
        channel = self.safe_string(message, 'channel')
        limit = self.safe_integer(subscription, 'limit')
        symbol = self.safe_string(subscription, 'symbol')
        orderbook = self.safe_value(self.orderbooks, symbol)
        if orderbook is None:
            orderbook = self.order_book({}, limit)
            self.orderbooks[symbol] = orderbook
        timestamp = self.safe_integer(message, 'lastTime')
        parsed = self.parse_order_book(message, symbol, timestamp, 'listDown', 'listUp')
        orderbook.reset(parsed)
        orderbook['symbol'] = symbol
        client.resolve(orderbook, channel)

    def handle_message(self, client, message):
        #
        #
        #     {
        #         no: '0',
        #         code: 1007,
        #         success: False,
        #         channel: 'btc_usdt_ticker',
        #         message: 'Channel is empty'
        #     }
        #
        #     {
        #         date: '1624398991255',
        #         ticker: {
        #             high: '33298.38',
        #             vol: '56375.9469',
        #             last: '32396.95',
        #             low: '28808.19',
        #             buy: '32395.81',
        #             sell: '32409.3',
        #             turnover: '1771122527.0000',
        #             open: '31652.44',
        #             riseRate: '2.36'
        #         },
        #         dataType: 'ticker',
        #         channel: 'btcusdt_ticker'
        #     }
        #
        #     {
        #         data: [
        #             {date: 1624537147, amount: '0.0357', price: '34066.11', trade_type: 'bid', type: 'buy', tid: 1718857158},
        #             {date: 1624537147, amount: '0.0255', price: '34071.04', trade_type: 'bid', type: 'buy', tid: 1718857159},
        #             {date: 1624537147, amount: '0.0153', price: '34071.29', trade_type: 'bid', type: 'buy', tid: 1718857160}
        #         ],
        #         dataType: 'trades',
        #         channel: 'btcusdt_trades'
        #     }
        #
        dataType = self.safe_string(message, 'dataType')
        if dataType is not None:
            channel = self.safe_string(message, 'channel')
            subscription = self.safe_value(client.subscriptions, channel)
            if subscription is not None:
                method = self.safe_value(subscription, 'method')
                if method is not None:
                    return method(client, message, subscription)
            return message
