# -*- 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

import ccxt.async_support
from ccxt.async_support.base.ws.cache import ArrayCache
from ccxt.base.types import Any, Int, OrderBook, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List


class tradeogre(ccxt.async_support.tradeogre):

    def describe(self) -> Any:
        return self.deep_extend(super(tradeogre, self).describe(), {
            'has': {
                'ws': True,
                'watchTrades': True,
                'watchTradesForSymbols': True,
                'watchOrderBook': True,
                'watchOrderBookForSymbols': False,
                'watchOHLCV': False,
                'watchOHLCVForSymbols': False,
                'watchOrders': False,
                'watchMyTrades': False,
                'watchTicker': False,
                'watchTickers': False,
                'watchBidsAsks': False,
                'watchBalance': False,
                'createOrderWs': False,
                'editOrderWs': False,
                'cancelOrderWs': False,
                'cancelOrdersWs': False,
            },
            'urls': {
                'api': {
                    'ws': 'wss://tradeogre.com:8443',
                },
            },
            'options': {
            },
            'streaming': {
            },
        })

    async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """
        watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data

        https://tradeogre.com/help/api

        :param str symbol: unified symbol of the market to fetch the order book for
        :param int [limit]: the maximum amount of order book entries to return(not used by the exchange)
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
        """
        await self.load_markets()
        market = self.market(symbol)
        url = self.urls['api']['ws']
        messageHash = 'orderbook' + ':' + market['symbol']
        request: dict = {
            'a': 'subscribe',
            'e': 'book',
            't': market['id'],
        }
        orderbook = await self.watch(url, messageHash, self.extend(request, params), messageHash)
        return orderbook.limit()

    def handle_order_book(self, client: Client, message):
        #
        # initial snapshot is fetched with ccxt's fetchOrderBook
        # the feed does not include a snapshot, just the deltas
        #
        #     {
        #         "e": "book",
        #         "t": "ETH-USDT",
        #         "s": "10752324",
        #         "d": {
        #             "bids": {"1787.02497915": "0"},
        #             "asks": {}
        #         }
        #     }
        #
        marketId = self.safe_string(message, 't')
        symbol = self.safe_symbol(marketId)
        if not (symbol in self.orderbooks):
            self.orderbooks[symbol] = self.order_book({})
        storedOrderBook = self.orderbooks[symbol]
        nonce = self.safe_integer(storedOrderBook, 'nonce')
        deltaNonce = self.safe_integer(message, 's')
        messageHash = 'orderbook:' + symbol
        if nonce is None:
            cacheLength = len(storedOrderBook.cache)
            snapshotDelay = self.handle_option('watchOrderBook', 'snapshotDelay', 6)
            if cacheLength == snapshotDelay:
                self.spawn(self.load_order_book, client, messageHash, symbol, None, {})
            storedOrderBook.cache.append(message)
            return
        elif nonce >= deltaNonce:
            return
        self.handle_delta(storedOrderBook, message)
        client.resolve(storedOrderBook, messageHash)

    def handle_delta(self, orderbook, delta):
        # timestamp = self.milliseconds()  # todo check if self is correct
        # orderbook['timestamp'] = timestamp
        # orderbook['datetime'] = self.iso8601(timestamp)
        orderbook['nonce'] = self.safe_integer(delta, 's')
        data = self.safe_dict(delta, 'd', {})
        bids = self.safe_dict(data, 'bids', {})
        asks = self.safe_dict(data, 'asks', {})
        storedBids = orderbook['bids']
        storedAsks = orderbook['asks']
        self.handle_bid_asks(storedBids, bids)
        self.handle_bid_asks(storedAsks, asks)

    def handle_bid_asks(self, bookSide, bidAsks):
        keys = list(bidAsks.keys())
        for i in range(0, len(keys)):
            price = self.safe_string(keys, i)
            amount = self.safe_number(bidAsks, price)
            bidAsk = [self.parse_number(price), amount]
            bookSide.storeArray(bidAsk)
        # for i in range(0, len(bidAsks)):
        #     bidAsk = self.parse_bid_ask(bidAsks[i])
        #     bookSide.storeArray(bidAsk)
        # }

    def get_cache_index(self, orderbook, deltas):
        firstElement = deltas[0]
        firstElementNonce = self.safe_integer(firstElement, 's')
        nonce = self.safe_integer(orderbook, 'nonce')
        if nonce < firstElementNonce:
            return -1
        for i in range(0, len(deltas)):
            delta = deltas[i]
            deltaNonce = self.safe_integer(delta, 's')
            if deltaNonce == nonce:
                return i + 1
        return len(deltas)

    async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """
        watches information on multiple trades made in a market

        https://tradeogre.com/help/api

        :param str symbol: unified market symbol of the market trades were made in
        :param int [since]: the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trade structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        symbol = market['symbol']
        return await self.watch_trades_for_symbols([symbol], since, limit, params)

    async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """

        https://tradeogre.com/help/api

        get the list of most recent trades for a list of symbols
        :param str[] symbols: unified symbol of the market to fetch trades for(empty array means all markets)
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
        """
        await self.load_markets()
        symbols = self.market_symbols(symbols, None, True)
        messageHashes = []
        symbolsLength = 0
        if symbols is not None:
            symbolsLength = len(symbols)
        if symbolsLength > 0:
            for i in range(0, len(symbols)):
                symbol = symbols[i]
                messageHash = 'trades:' + symbol
                messageHashes.append(messageHash)
        else:
            messageHash = 'trades'
            messageHashes.append(messageHash)
        request: dict = {
            'a': 'subscribe',
            'e': 'trade',
            't': '*',
        }
        url = self.urls['api']['ws']
        trades = await self.watch_multiple(url, messageHashes, self.extend(request, params), ['trades'])
        if self.newUpdates:
            first = self.safe_dict(trades, 0)
            tradeSymbol = self.safe_string(first, 'symbol')
            limit = trades.getLimit(tradeSymbol, limit)
        return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)

    def handle_trade(self, client: Client, message):
        #
        #     {
        #         "e": "trade",
        #         "t": "LTC-USDT",
        #         "d": {
        #             "t": 0,
        #             "p": "84.50000000",
        #             "q": "1.28471270",
        #             "d": "1745392002"
        #         }
        #     }
        #
        marketId = self.safe_string(message, 't')
        market = self.safe_market(marketId)
        data = self.safe_dict(message, 'd', {})
        symbol = market['symbol']
        if not (symbol in self.trades):
            limit = self.safe_integer(self.options, 'tradesLimit', 1000)
            stored = ArrayCache(limit)
            self.trades[symbol] = stored
        cache = self.trades[symbol]
        trade = self.parse_ws_trade(data, market)
        cache.append(trade)
        messageHash = 'trades:' + symbol
        client.resolve(cache, messageHash)
        client.resolve(cache, 'trades')

    def parse_ws_trade(self, trade, market=None):
        #
        #     {
        #         "t": 0,
        #         "p": "84.50000000",
        #         "q": "1.28471270",
        #         "d": "1745392002"
        #     }
        #
        timestamp = self.safe_integer_product(trade, 'd', 1000)
        sideEnum = self.safe_string(trade, 't')
        return self.safe_trade({
            'info': trade,
            'id': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': self.safe_string(market, 'symbol'),
            'order': None,
            'type': None,
            'side': self.parse_ws_trade_side(sideEnum),
            'takerOrMaker': None,
            'price': self.safe_string(trade, 'p'),
            'amount': self.safe_string(trade, 'q'),
            'cost': None,
            'fee': {
                'currency': None,
                'cost': None,
            },
        }, market)

    def parse_ws_trade_side(self, side):
        sides = {
            '0': 'buy',
            '1': 'sell',
        }
        return self.safe_string(sides, side, side)

    def handle_message(self, client: Client, message):
        methods: dict = {
            'book': self.handle_order_book,
            'trade': self.handle_trade,
        }
        event = self.safe_string(message, 'e')
        method = self.safe_value(methods, event)
        if method is not None:
            method(client, message)
