from collections import deque,OrderedDict
import unittest,random
import itertools
from hera.views import in_city_white_list
from .cache import redis_client


def drop_dup(items):
    duplicates = set()
    def check(item):
        if item[1] in duplicates:
            return False
        else:
            duplicates.add(item[1])
            return True
    return list(filter(check, items))


def drop_dup2(items):
    duplicates = set()
    def check(item):
        if item["dup"] in duplicates:
            return False
        else:
            duplicates.add(item["dup"])
            return True
    return list(filter(check, items))


def variousness_for_problem(items, drop_duplicated, variety_size):
    import traceback
    src = deque(items)
    dst = []
    while len(src) > 0:
        pos, temp, recover, dup, diary_id_set = 0, [], [],[], set()
        while pos < variety_size:
            try:
                item = src.popleft()

                if item["type"] == 0:
                    if drop_duplicated and item.get("group") in dup:
                        recover.append(item)
                    else:
                        temp.append(item)
                        dup.append(item.get("group"))
                        pos = pos+1
                else:
                    if item["diary_id"] in diary_id_set:
                        recover.append(item)
                    else:
                        temp.append(item)
                        dup.append(item["id"])
                        diary_id_set.add(item["diary_id"])
                        pos = pos + 1

            except IndexError as  e:
                diff = variety_size - pos
                diff, remain = recover[:diff], recover[diff:]
                temp.extend(diff)
                recover = remain
                break
        multi = OrderedDict()

        for key in dup:
            multi[key] = []
        for item in temp:
            if item["type"] == 0:
                multi[item.get("group")].append(item)
            else:
                multi[item["id"]] = [item]
        temp = filter(lambda a: a!=None,itertools.chain.from_iterable(itertools.zip_longest(*multi.values())))

        dst.extend(temp)
        src.extendleft(reversed(recover))

    return dst

def variousness(items, variety_size):
    src = deque(items)
    dst = []
    while len(src) > 0:
        pos, temp, recover, dup = 0, [], [],[]
        while pos < variety_size:
            try:
                item = src.popleft()
                if item.get("group") in dup:
                    recover.append(item)
                else:
                    temp.append(item)
                    dup.append(item.get("group"))
                    pos = pos+1
            except IndexError:
                diff = variety_size - pos
                diff, remain = recover[:diff], recover[diff:]
                temp.extend(diff)
                recover = remain
                break
        multi = OrderedDict()
        for key in dup:
            multi[key] = []
        for item in temp:
            multi[item.get("group")].append(item)
        temp = filter(lambda a: a!=None,itertools.chain.from_iterable(itertools.zip_longest(*multi.values())))

        dst.extend(temp)
        src.extendleft(reversed(recover))

    return dst

def region_division(items, current_city):
    city, nearby, other = [], [], []
    for item in items:
        if current_city == item.get("city"):
            city.append(item)
        elif current_city in item.get("nearby"):
            nearby.append(item)
        else:
            other.append(item)
    if in_city_white_list(current_city):
        return [city, nearby, other]
    return [city + nearby, other]


class VariousnessTestCase(unittest.TestCase):

    def test_hello(self):
        dup_collction = ["a","b","c"]
        tests = []
        result = []
        for i in range(1000):
            result.append(i)
            tests.append(({"id":i,"group":random.choice(dup_collction)}))

        print(tests)

        dst = variousness(tests,10)
        dst2 = variousness(tests,10)
        print(dst)
        assert dst == dst2
        answer = []
        for item in dst:
            answer.append(item['id'])
        answer.sort()

        assert answer == result

if __name__ == "__main__":
    unittest.main()