# -*- 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, Market, OrderBook, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import AuthenticationError


class coincheck(ccxt.async_support.coincheck):

    def describe(self) -> Any:
        return self.deep_extend(super(coincheck, self).describe(), {
            'has': {
                'ws': True,
                'watchOrderBook': True,
                'watchOrders': False,
                'watchTrades': True,
                'watchTradesForSymbols': False,
                'watchOHLCV': False,
                'watchTicker': False,
                'watchTickers': False,
            },
            'urls': {
                'api': {
                    'ws': 'wss://ws-api.coincheck.com/',
                },
            },
            'options': {
                'expiresIn': '',
                'userId': '',
                'wsSessionToken': '',
                'watchOrderBook': {
                    'snapshotDelay': 6,
                    'snapshotMaxRetries': 3,
                },
                'tradesLimit': 1000,
                'OHLCVLimit': 1000,
            },
            'exceptions': {
                'exact': {
                    '4009': AuthenticationError,
                },
            },
        })

    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://coincheck.com/documents/exchange/api#websocket-order-book

        :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
        :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)
        messageHash = 'orderbook:' + market['symbol']
        url = self.urls['api']['ws']
        request: dict = {
            'type': 'subscribe',
            'channel': market['id'] + '-orderbook',
        }
        message = self.extend(request, params)
        orderbook = await self.watch(url, messageHash, message, messageHash)
        return orderbook.limit()

    def handle_order_book(self, client, message):
        #
        #     [
        #         "btc_jpy",
        #         {
        #             "bids": [
        #                 [
        #                     "6288279.0",
        #                     "0"
        #                 ]
        #             ],
        #             "asks": [
        #                 [
        #                     "6290314.0",
        #                     "0"
        #                 ]
        #             ],
        #             "last_update_at": "1705396097"
        #         }
        #     ]
        #
        symbol = self.symbol(self.safe_string(message, 0))
        data = self.safe_value(message, 1, {})
        timestamp = self.safe_timestamp(data, 'last_update_at')
        snapshot = self.parse_order_book(data, symbol, timestamp)
        orderbook = self.safe_value(self.orderbooks, symbol)
        if orderbook is None:
            orderbook = self.order_book(snapshot)
            self.orderbooks[symbol] = orderbook
        else:
            orderbook = self.orderbooks[symbol]
            orderbook.reset(snapshot)
        messageHash = 'orderbook:' + symbol
        client.resolve(orderbook, messageHash)

    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://coincheck.com/documents/exchange/api#websocket-trades

        :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']
        messageHash = 'trade:' + market['symbol']
        url = self.urls['api']['ws']
        request: dict = {
            'type': 'subscribe',
            'channel': market['id'] + '-trades',
        }
        message = self.extend(request, params)
        trades = await self.watch(url, messageHash, message, messageHash)
        if self.newUpdates:
            limit = trades.getLimit(symbol, limit)
        return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)

    def handle_trades(self, client: Client, message):
        #
        #     [
        #         [
        #             "1663318663",  # transaction timestamp(unix time)
        #             "2357062",  # transaction ID
        #             "btc_jpy",  # pair
        #             "2820896.0",  # transaction rate
        #             "5.0",  # transaction amount
        #             "sell",  # order side
        #             "1193401",  # ID of the Taker
        #             "2078767"  # ID of the Maker
        #         ]
        #     ]
        #
        first = self.safe_value(message, 0, [])
        symbol = self.symbol(self.safe_string(first, 2))
        stored = self.safe_value(self.trades, symbol)
        if stored is None:
            limit = self.safe_integer(self.options, 'tradesLimit', 1000)
            stored = ArrayCache(limit)
            self.trades[symbol] = stored
        for i in range(0, len(message)):
            data = self.safe_value(message, i)
            trade = self.parse_ws_trade(data)
            stored.append(trade)
        messageHash = 'trade:' + symbol
        client.resolve(stored, messageHash)

    def parse_ws_trade(self, trade: dict, market: Market = None) -> Trade:
        #
        #     [
        #         "1663318663",  # transaction timestamp(unix time)
        #         "2357062",  # transaction ID
        #         "btc_jpy",  # pair
        #         "2820896.0",  # transaction rate
        #         "5.0",  # transaction amount
        #         "sell",  # order side
        #         "1193401",  # ID of the Taker
        #         "2078767"  # ID of the Maker
        #     ]
        #
        symbol = self.symbol(self.safe_string(trade, 2))
        timestamp = self.safe_timestamp(trade, 0)
        side = self.safe_string(trade, 5)
        priceString = self.safe_string(trade, 3)
        amountString = self.safe_string(trade, 4)
        return self.safe_trade({
            'id': self.safe_string(trade, 1),
            'info': trade,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'order': None,
            'symbol': symbol,
            'type': None,
            'side': side,
            'takerOrMaker': None,
            'price': priceString,
            'amount': amountString,
            'cost': None,
            'fee': None,
        }, market)

    def handle_message(self, client: Client, message):
        data = self.safe_value(message, 0)
        if not isinstance(data, list):
            self.handle_order_book(client, message)
        else:
            self.handle_trades(client, message)
