import os
import sys

root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
sys.path.append(root)

# ----------------------------------------------------------------------------

# 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.ws.cache import ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById  # noqa: F402


def equals(a, b):
    return a == b


# ----------------------------------------------------------------------------

cache = ArrayCache(3)

cache.append({'symbol': 'BTC/USDT', 'data': 1})
cache.append({'symbol': 'BTC/USDT', 'data': 2})
cache.append({'symbol': 'BTC/USDT', 'data': 3})
cache.append({'symbol': 'BTC/USDT', 'data': 4})

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'data': 2},
    {'symbol': 'BTC/USDT', 'data': 3},
    {'symbol': 'BTC/USDT', 'data': 4},
]))

cache.append({'symbol': 'BTC/USDT', 'data': 5})
cache.append({'symbol': 'BTC/USDT', 'data': 6})
cache.append({'symbol': 'BTC/USDT', 'data': 7})
cache.append({'symbol': 'BTC/USDT', 'data': 8})

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'data': 6},
    {'symbol': 'BTC/USDT', 'data': 7},
    {'symbol': 'BTC/USDT', 'data': 8},
]))

cache.clear()

cache.append({'symbol': 'BTC/USDT', 'data': 1})

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'data': 1},
]))

# ----------------------------------------------------------------------------

cache = ArrayCache(1)

cache.append({'symbol': 'BTC/USDT', 'data': 1})
cache.append({'symbol': 'BTC/USDT', 'data': 2})

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'data': 2},
]))

# ----------------------------------------------------------------------------

cache = ArrayCacheByTimestamp()

ohlcv1 = [100, 1, 2, 3]
ohlcv2 = [200, 5, 6, 7]
cache.append(ohlcv1)
cache.append(ohlcv2)

assert equals(cache, [ohlcv1, ohlcv2])

modify2 = [200, 10, 11, 12]
cache.append(modify2)

assert equals(cache, [ohlcv1, modify2])

# ----------------------------------------------------------------------------

cache = ArrayCacheBySymbolById()

object1 = {'symbol': 'BTC/USDT', 'id': 'abcdef', 'i': 1}
object2 = {'symbol': 'ETH/USDT', 'id': 'qwerty', 'i': 2}
object3 = {'symbol': 'BTC/USDT', 'id': 'abcdef', 'i': 3}
cache.append(object1)
cache.append(object2)
cache.append(object3)  # should update index 0

assert equals(cache, [object2, object3])

cache = ArrayCacheBySymbolById(5)

for i in range(1, 11):
    cache.append({
        'symbol': 'BTC/USDT',
        'id': str(i),
        'i': i,
    })

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'id': '6', 'i': 6},
    {'symbol': 'BTC/USDT', 'id': '7', 'i': 7},
    {'symbol': 'BTC/USDT', 'id': '8', 'i': 8},
    {'symbol': 'BTC/USDT', 'id': '9', 'i': 9},
    {'symbol': 'BTC/USDT', 'id': '10', 'i': 10},
]))

for i in range(1, 11):
    cache.append({
        'symbol': 'BTC/USDT',
        'id': str(i),
        'i': i + 10,
    })

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'id': '6', 'i': 16},
    {'symbol': 'BTC/USDT', 'id': '7', 'i': 17},
    {'symbol': 'BTC/USDT', 'id': '8', 'i': 18},
    {'symbol': 'BTC/USDT', 'id': '9', 'i': 19},
    {'symbol': 'BTC/USDT', 'id': '10', 'i': 20},
]))

middle = {'symbol': 'BTC/USDT', 'id': '8', 'i': 28}
cache.append(middle)

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'id': '6', 'i': 16},
    {'symbol': 'BTC/USDT', 'id': '7', 'i': 17},
    {'symbol': 'BTC/USDT', 'id': '9', 'i': 19},
    {'symbol': 'BTC/USDT', 'id': '10', 'i': 20},
    {'symbol': 'BTC/USDT', 'id': '8', 'i': 28},
]))

otherMiddle = {'symbol': 'BTC/USDT', 'id': '7', 'i': 27}
cache.append(otherMiddle)

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'id': '6', 'i': 16},
    {'symbol': 'BTC/USDT', 'id': '9', 'i': 19},
    {'symbol': 'BTC/USDT', 'id': '10', 'i': 20},
    {'symbol': 'BTC/USDT', 'id': '8', 'i': 28},
    {'symbol': 'BTC/USDT', 'id': '7', 'i': 27},
]))

for i in range(30, 33):
    cache.append({
        'symbol': 'BTC/USDT',
        'id': str(i),
        'i': i + 10,
    })

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'id': '8', 'i': 28},
    {'symbol': 'BTC/USDT', 'id': '7', 'i': 27},
    {'symbol': 'BTC/USDT', 'id': '30', 'i': 40},
    {'symbol': 'BTC/USDT', 'id': '31', 'i': 41},
    {'symbol': 'BTC/USDT', 'id': '32', 'i': 42}]))

first = {'symbol': 'BTC/USDT', 'id': '8', 'i': 38}
cache.append(first)

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'id': '7', 'i': 27},
    {'symbol': 'BTC/USDT', 'id': '30', 'i': 40},
    {'symbol': 'BTC/USDT', 'id': '31', 'i': 41},
    {'symbol': 'BTC/USDT', 'id': '32', 'i': 42},
    {'symbol': 'BTC/USDT', 'id': '8', 'i': 38},
]))

another = {'symbol': 'BTC/USDT', 'id': '30', 'i': 50}
cache.append(another)

assert(equals(cache, [
    {'symbol': 'BTC/USDT', 'id': '7', 'i': 27},
    {'symbol': 'BTC/USDT', 'id': '31', 'i': 41},
    {'symbol': 'BTC/USDT', 'id': '32', 'i': 42},
    {'symbol': 'BTC/USDT', 'id': '8', 'i': 38},
    {'symbol': 'BTC/USDT', 'id': '30', 'i': 50},
]))

# ----------------------------------------------------------------------------

# test ArrayCacheBySymbolById limit with symbol set
symbol = 'BTC/USDT'
cache = ArrayCacheBySymbolById()
initialLength = 5
for i in range(0, initialLength):
    cache.append({
        'symbol': symbol,
        'id': str(i),
        'i': i,
    })

limited = cache.getLimit(symbol, None)

assert initialLength == limited

cache = ArrayCacheBySymbolById()
appendItemsLength = 3
for i in range(0, appendItemsLength):
    cache.append({
        'symbol': symbol,
        'id': str(i),
        'i': i,
    })

outsideLimit = 5
limited = cache.getLimit(symbol, outsideLimit)

assert appendItemsLength == limited

outsideLimit = 2  # if limit < newsUpdate that should be returned
limited = cache.getLimit(symbol, outsideLimit)

assert outsideLimit == limited

# ----------------------------------------------------------------------------

# test ArrayCacheBySymbolById limit with symbol None
symbol = 'BTC/USDT'
cache = ArrayCacheBySymbolById()
initialLength = 5
for i in range(0, initialLength):
    cache.append({
        'symbol': symbol,
        'id': str(i),
        'i': i,
    })

limited = cache.getLimit(None, None)

assert initialLength == limited

cache = ArrayCacheBySymbolById()
appendItemsLength = 3
for i in range(0, appendItemsLength):
    cache.append({
        'symbol': symbol,
        'id': str(i),
        'i': i,
    })

outsideLimit = 5
limited = cache.getLimit(symbol, outsideLimit)

assert appendItemsLength == limited

outsideLimit = 2  # if limit < newsUpdate that should be returned
limited = cache.getLimit(symbol, outsideLimit)

assert outsideLimit == limited


# ----------------------------------------------------------------------------
# test ArrayCacheBySymbolById, same order should not increase the limit

cache = ArrayCacheBySymbolById()
symbol = 'BTC/USDT'
otherSymbol = 'ETH/USDT'

cache.append({'symbol': symbol, 'id': 'singleId', 'i': 3})
cache.append({'symbol': symbol, 'id': 'singleId', 'i': 3})
cache.append({'symbol': otherSymbol, 'id': 'singleId', 'i': 3})
outsideLimit = 5
limited = cache.getLimit(symbol, outsideLimit)
limited2 = cache.getLimit(None, outsideLimit)

assert limited == 1
assert limited2 == 2


# ----------------------------------------------------------------------------
# test testLimitArrayCacheByTimestamp limit

cache = ArrayCacheByTimestamp()

initialLength = 5
for i in range(0, initialLength):
    cache.append([
        i * 10,
        i * 10,
        i * 10,
        i * 10
    ])

limited = cache.getLimit(None, None)

assert initialLength == limited

appendItemsLength = 3
for i in range(0, appendItemsLength):
    cache.append([
        i * 4,
        i * 4,
        i * 4,
        i * 4
    ])

outsideLimit = 5
limited = cache.getLimit(None, outsideLimit)

assert appendItemsLength == limited

outsideLimit = 2  # if limit < newsUpdate that should be returned
limited = cache.getLimit(None, outsideLimit)

assert outsideLimit == limited


# ----------------------------------------------------------------------------
# test ArrayCacheBySymbolById, watch all orders, same symbol and order id gets updated

cache = ArrayCacheBySymbolById()
symbol = 'BTC/USDT'
outsideLimit = 5
cache.append({'symbol': symbol, 'id': 'oneId', 'i': 3})  # create first order
cache.getLimit(None, outsideLimit)  # watch all orders
cache.append({'symbol': symbol, 'id': 'oneId', 'i': 4})  # first order is closed
cache.getLimit(None, outsideLimit)  # watch all orders
cache.append({'symbol': symbol, 'id': 'twoId', 'i': 5})  # create second order
cache.getLimit(None, outsideLimit)  # watch all orders
cache.append({'symbol': symbol, 'id': 'twoId', 'i': 6})  # second order is closed
limited = cache.getLimit(None, outsideLimit)  # watch all orders
assert limited == 1  # one new update

# ----------------------------------------------------------------------------
# test ArrayCacheBySymbolById, watch all orders, and watchOrders(symbol) work independently

cache = ArrayCacheBySymbolById()
symbol = 'BTC/USDT'
symbol2 = 'ETH/USDT'

outsideLimit = 5
cache.append({'symbol': symbol, 'id': 'one', 'i': 1})  # create first order
cache.append({'symbol': symbol2, 'id': 'two', 'i': 1})  # create second order
assert cache.getLimit(None, outsideLimit) == 2  # watch all orders
assert cache.getLimit(symbol, outsideLimit) == 1  # watch by symbol
cache.append({'symbol': symbol, 'id': 'one', 'i': 2})  # update first order
cache.append({'symbol': symbol2, 'id': 'two', 'i': 2})  # update second order
assert cache.getLimit(symbol, outsideLimit) == 1  # watch by symbol
assert cache.getLimit(None, outsideLimit) == 2  # watch all orders
cache.append({'symbol': symbol2, 'id': 'two', 'i': 3})  # update second order
cache.append({'symbol': symbol2, 'id': 'three', 'i': 3})  # create third order
assert cache.getLimit(None, outsideLimit) == 2  # watch all orders
