import unittest
from feedly.storage.redis.structures.hash import RedisHashCache,\
    ShardedHashCache, FallbackHashCache
from feedly.storage.redis.structures.list import RedisListCache,\
    FallbackRedisListCache
from feedly.storage.redis.connection import get_redis_connection
from functools import partial
from feedly.storage.redis.structures.sorted_set import RedisSortedSetCache


class BaseRedisStructureTestCase(unittest.TestCase):

    def get_structure(self):
        return


class RedisSortedSetTest(BaseRedisStructureTestCase):

    test_data = [(1.0, 'a'), (2.0, 'b'), (3.0, 'c')]

    def get_structure(self):
        structure_class = RedisSortedSetCache
        structure = structure_class('test')
        structure.delete()
        return structure

    def test_add_many(self):
        cache = self.get_structure()
        test_data = self.test_data
        for key, value in test_data:
            cache.add(key, value)
        # this shouldnt insert data, its a sorted set after all
        cache.add_many(test_data)
        count = cache.count()
        self.assertEqual(int(count), 3)

    def test_ordering(self):
        cache = self.get_structure()
        data = self.test_data

        test_data = data
        cache.add_many(test_data)
        results = cache[:]
        expected_results = [p[::-1] for p in test_data]
        self.assertEqual(results, expected_results[::-1])
        cache.sort_asc = True
        results = cache[:10]
        self.assertEqual(results, expected_results)

    def test_trim(self):
        cache = self.get_structure()
        test_data = self.test_data
        for score, value in test_data:
            cache.add(score, value)
        cache.trim(1)
        count = cache.count()
        self.assertEqual(count, 1)

    def test_simple_trim(self):
        cache = self.get_structure()
        test_data = self.test_data
        for key, value in test_data:
            cache.add(key, value)
        cache.max_length = 1
        cache.trim()
        count = int(cache.count())
        self.assertEqual(count, 1)

    def test_remove(self):
        cache = self.get_structure()
        test_data = self.test_data
        cache.add_many(test_data)
        cache.remove_many(['a'])
        count = cache.count()
        self.assertEqual(count, 2)

    def test_remove_by_score(self):
        cache = self.get_structure()
        test_data = self.test_data
        cache.add_many(test_data)
        cache.remove_by_scores([1.0, 2.0])
        count = cache.count()
        self.assertEqual(count, 1)

    def test_zremrangebyrank(self):
        redis = get_redis_connection()
        key = 'test'
        # start out fresh
        redis.delete(key)
        redis.zadd(key, 1, 'a')
        redis.zadd(key, 2, 'b')
        redis.zadd(key, 3, 'c')
        redis.zadd(key, 4, 'd')
        redis.zadd(key, 5, 'e')
        expected_results = [('a', 1.0), ('b', 2.0), ('c', 3.0), (
            'd', 4.0), ('e', 5.0)]
        results = redis.zrange(key, 0, -1, withscores=True)
        self.assertEqual(results, expected_results)
        results = redis.zrange(key, 0, -4, withscores=True)

        # now the idea is to only keep 3,4,5
        max_length = 3
        end = (max_length * -1) - 1
        redis.zremrangebyrank(key, 0, end)
        expected_results = [('c', 3.0), ('d', 4.0), ('e', 5.0)]
        results = redis.zrange(key, 0, -1, withscores=True)
        self.assertEqual(results, expected_results)


class ListCacheTestCase(BaseRedisStructureTestCase):

    def get_structure(self):
        structure_class = type(
            'MyCache', (RedisListCache, ), dict(max_items=10))
        structure = structure_class('test')
        structure.delete()
        return structure

    def test_append(self):
        cache = self.get_structure()
        cache.append_many(['a', 'b'])
        self.assertEqual(cache[:5], ['a', 'b'])
        self.assertEqual(cache.count(), 2)

    def test_simple_append(self):