# -*- 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.base.exchange import Exchange
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import PermissionDenied
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import DDoSProtection
from ccxt.base.errors import ExchangeNotAvailable
from ccxt.base.errors import InvalidNonce


class coinsuper(Exchange):

    def describe(self):
        return self.deep_extend(super(coinsuper, self).describe(), {
            'id': 'coinsuper',
            'name': 'CoinSuper',
            'countries': ['CN'],
            'rateLimit': 200,
            'version': 'v1',
            'has': {
                'CORS': False,
                'fetchTrades': True,
                'fetchTicker': False,
                'fetchTickers': False,
                'fetchOrder': False,  # True,
                'fetchOrders': False,  # True,
                'fetchOpenOrders': False,  # True,
                'fetchClosedOrders': False,
                'fetchOHLCV': True,
                'fetchBalance': False,  # True,
                'cancelOrder': False,  # True,
                'cancelOrders': False,  # True,
            },
            'timeframes': {
                '5m': '5min',
                '15m': '15min',
                '30m': '30min',
                '1h': '1hour',
                '6h': '6hour',
                '12h': '12hour',
                '1d': '1day',
            },
            'urls': {
                'logo': 'https://www.coinsuper' + '.com/api/docs/v1/images/logo.png',
                'api': {
                    'public': 'https://api.coinsuper' + '.com',
                    'private': 'https://api.coinsuper' + '.com/api',
                },
                'www': 'https://coinsuper' + '.com',
                'doc': 'https://www.coinsuper' + '.com/api/docs/v1/api_en.html',
                'fees': 'https://support.coinsuper' + '.info/hc/en-gb/articles/360020538154-Fees-Schedule',
            },
            'api': {
                'public': {
                    'get': [
                    ],
                },
                'private': {
                    'post': [
                        'market/orderBook',
                        'market/kline',
                        'market/tickers',
                        'market/symbolList',
                        'order/buy',
                        'order/sell',
                        'order/cancel',
                        'order/batchCancel',
                        'asset/userAssetInfo',
                        'order/list',
                        'order/details',
                        'order/clList',
                        'order/openList',
                        'order/history',
                        'order/tradeHistory',
                    ],
                },
                'options': {
                    # 'defaultTimeInForce': 'FOK',
                },
            },
            'exceptions': {
                '2000': ExchangeNotAvailable,  # 'system upgrading',
                '2001': 'system internal error',
                '2002': 'interface is unavailability',
                '2003': DDoSProtection,  # request is too frequently,
                '2004': PermissionDenied,  # fail to check sign
                '2005': ArgumentsRequired,  # parameter is invalid,
                '2006': 'request failure',
                '2007': PermissionDenied,  # 'accesskey has been forbidden',
                '2008': 'user not exist',
                '3001': InsufficientFunds,  # 'account balance is not enough',
                '3002': OrderNotFound,  # 'orderNo is not exist',
                '3003': 'price is invalid',
                '3004': 'symbol is invalid',
                '3005': 'quantity is invalid',
                '3006': 'ordertype is invalid',
                '3007': 'action is invalid',
                '3008': 'state is invalid',
                '3009': InvalidNonce,  # 'num is invalid',
                '3010': 'amount is invalid',
                '3011': 'cancel order failure',
                '3012': 'create order failure',
                '3013': 'orderList is invalid',
                '3014': 'symbol not trading',
                '3015': 'order amount or quantity less than min setting',
                '3016': 'price greater than max setting',
                '3017': AuthenticationError,  # 'user account forbidden',
                '3018': 'order has execute',
                '3019': 'orderNo num is more than the max setting',
                '3020': 'price out of range',
                '3021': 'order has canceled',
                '3027': 'this symbols API trading channel is not available',
                '3028': 'duplicate clientOrderId',
                '3029': 'Market price deviation is too large, market order is not recommended',
                '3030': 'Market price deviation is too large, market order is not recommended',
                '3031': 'batch create order more or less than limit',
                '3032': 'batch create order symbol not unique',
                '3033': 'batch create order action not unique',
                '3034': 'clientOrderIdList and orderNoList should and only pass one',
                '3035': 'order cancel param error',
                '3036': 'not usual ip',
            },
            'requiredCredentials': {
                'apiKey': True,
                'secret': True,
            },
        })

    def fetch_markets(self, params={}):
        response = self.privatePostMarketSymbolList(params)
        markets = self.safe_value(response['data'], 'result')
        result = []
        for i in range(0, len(markets)):
            market = markets[i]
            id = self.safe_string(market, 'symbol')
            [baseId, quoteId] = id.split('/')
            base = baseId.upper()
            quote = quoteId.upper()
            base = self.safe_currency_code(base)
            quote = self.safe_currency_code(quote)
            symbol = base + '/' + quote
            precision = {
                'amount': self.safe_integer(market, 'quantityScale'),
                'price': self.safe_integer(market, 'priceScale'),
                'totalPrice': self.safe_integer(market, 'amountScale')
            }
            amountLimits = {
                'min': self.safe_float(market, 'quantityMin'),
                'max': self.safe_float(market, 'quantityMax')
            }
            marketTotalLimits = {
                'min': self.safe_float(market, 'priceMin'),
                'max': self.safe_float(market, 'priceMax')
            }
            deviationRatio = {
                'deviation': self.safe_float(market, 'deviationRatio')
            }
            limits = {
                'amount': amountLimits,
                'price': marketTotalLimits,
                'cost': {
                    'min': None,
                    'max': None
                },
                'deviationRatio': deviationRatio
            }
            result.append({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': True,
                'precision': precision,
                'limits': limits,
                'info': market
            })
        return result

    def fetch_order_book(self, symbol, limit=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOrderBook requires a `symbol` argument')
        market = self.market(symbol)
        self.load_markets()
        if limit is None or limit > 50:
            limit = 50
        request = {
            'symbol': market['id'],
            'num': limit
        }
        response = self.privatePostMarketOrderBook(self.extend(request, params))
        orderbook = self.safe_value(response['data'], 'result', {})
        timeStamp = self.safe_value(response['data'], 'timestamp', {})
        return self.parse_order_book(orderbook, timeStamp, 'bids', 'asks', 'limitPrice', 'quantity')

    def fetch_ohlcv(self, symbol, timeframe='5m', since=None, limit=None, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchOHLCV requires a `symbol` argument')
        self.load_markets()
        market = self.market(symbol)
        if limit is None or limit > 300:
            limit = 300
        request = {
            'symbol': market['id'],
            'range': self.timeframes[timeframe],
            'num': limit
        }
        response = self.privatePostMarketKline(self.extend(request, params))
        data = self.safe_value(response['data'], 'result', {})
        return self.parse_ohlcvs(data, market, timeframe, since, limit)

    def parse_ohlcv(self, ohlcv, market=None):
        return [
            self.safe_integer(ohlcv, 'timestamp'),
            self.safe_float(ohlcv, 'open'),
            self.safe_float(ohlcv, 'high'),
            self.safe_float(ohlcv, 'low'),
            self.safe_float(ohlcv, 'close'),
            self.safe_float(ohlcv, 'volume'),
        ]

    def fetch_trades(self, symbol, params={}):
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchMyTrades requires a `symbol` argument')
        market = self.market(symbol)
        self.load_markets()
        request = {
            'symbol': market['id']
        }
        response = self.privatePostMarketTickers(self.extend(request, params))
        data = self.safe_value(response['data'], 'result', {})
        return self.parse_trades(data, market)

    def parse_trade(self, trade, market=None):
        timestamp = self.safe_integer(trade, 'timestamp')
        side = self.safe_string_lower(trade, 'tradeType')
        price = self.safe_float_2(trade, 'rate', 'price')
        id = self.safe_string_2(trade, 'trade_id', 'tid')
        order = self.safe_string(trade, 'order_id')
        if 'pair' in trade:
            marketId = self.safe_string(trade, 'pair')
            market = self.safe_value(self.markets_by_id, marketId, market)
        symbol = None
        if market is not None:
            symbol = market['symbol']
        amount = self.safe_float(trade, 'volume')
        type = 'limit'  # all trades are still limit trades
        takerOrMaker = None
        fee = None
        feeCost = self.safe_float(trade, 'commission')
        if feeCost is not None:
            feeCurrencyId = self.safe_string(trade, 'commissionCurrency')
            feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
            fee = {
                'cost': feeCost,
                'currency': feeCurrencyCode
            }
        isYourOrder = self.safe_value(trade, 'is_your_order')
        if isYourOrder is not None:
            takerOrMaker = 'taker'
            if isYourOrder:
                takerOrMaker = 'maker'
            if fee is None:
                fee = self.calculate_fee(symbol, type, side, amount, price, takerOrMaker)
        cost = None
        if amount is not None:
            if price is not None:
                cost = amount * price
        return {
            'id': id,
            'order': order,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'type': type,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': fee,
            'info': trade
        }

    def nonce(self):
        return self.milliseconds()

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        url = self.urls['api'][api] + '/' + self.version + '/' + path
        if api == 'public':
            url += '?' + self.urlencode(params)
            headers = {'Content-Type': 'application/json'}
        else:
            self.check_required_credentials()
            nonce = self.nonce()
            sigParams = self.extend({
                'timestamp': nonce,
                'accesskey': self.apiKey,
                'secretkey': self.secret
            }, params)
            # param alphabetical order is necessary, but urlencode doesn't preserve order(even if it is OrderedDict)
            # signature = self.rawencode(self.keysort(sigParams))
            # signature = self.urlencode(self.keysort(sigParams))
            signature = ''
            keys = list(self.keysort(sigParams).keys())
            for i in range(0, len(keys)):
                signature += '&' if (i > 0) else ''
                signature += keys[i] + '=' + str(sigParams[keys[i]])
            signature = self.hash(self.encode(signature), 'md5')
            body = self.extend({
                'common': {
                    'accesskey': self.apiKey,
                    'sign': signature,
                    'timestamp': nonce
                },
                'data': params
            })
            headers = {'Content-Type': 'application/json'}
            if body is not None:
                body = self.json(body, {'convertArraysToObjects': True})
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
        if response is None:
            return
        if 'code' in response:
            if response['code'] != '1000':
                code = self.safe_string(response, 'code')
                feedback = self.id + ' ' + body
                exceptions = self.exceptions
                if code in exceptions:
                    raise exceptions[code](feedback)
                else:
                    raise ExchangeError(feedback)
        if not ('result' in response['data']):
            raise ExchangeError(self.id + ' ' + body)
    #handleRestResponse(response, url, method = 'GET', requestHeaders = None, requestBody = None) {
    #    return response.text().then((responseBody) => {
    #        toBigNum = responseBody.replace(/:(\d{19,})/g, `:"$1"`)
    #        json = self.parse_json(toBigNum)
    #        responseHeaders = self.get_response_headers(response)
    #        if self.enableLastResponseHeaders:
    #            self.last_response_headers = responseHeaders
    #        }
    #        if self.enableLastHttpResponse:
    #            self.last_http_response = responseBody  # FIXME: for those classes that haven't switched to handleErrors yet
    #        }
    #        if self.enableLastJsonResponse:
    #            self.last_json_response = json         # FIXME: for those classes that haven't switched to handleErrors yet
    #        }
    #        if self.verbose:
    #            console.log("handleRestResponse:\n", self.id, method, url, response.status, response.statusText, "\nResponse:\n", responseHeaders, "\n", responseBody, "\n")
    #        }
    #        self.handle_errors(response.status, response.statusText, url, method, responseHeaders, responseBody, json, requestHeaders, requestBody)
    #        self.default_error_handler(response.status, response.statusText, url, method, responseHeaders, responseBody, json)
    #        return(json or responseBody)
    #    })
