# coding=utf-8
from __future__ import unicode_literals, print_function, absolute_import

import json

from gm_types.gaia import WORLD_AREA_TYPE

from api.tool.servicehome_tool import BasicServiceHomeFilter
from api.models import ServiceFilter, SERVICE_FILTER_TYPE
from distutils.version import LooseVersion


class ExtraFilter(object):
    """
    筛选器

    for 美购列表筛选条
    http://wiki.gengmei.cc/pages/viewpage.action?pageId=1050558
    """

    __subclasses = set()

    @classmethod
    def register(cls, subclass):
        assert issubclass(subclass, cls)
        cls.__subclasses.add(subclass)
        return subclass

    @classmethod
    def parse_string(cls, string):
        return cls.parse_jdict(json.loads(string))

    @classmethod
    def parse_jdict(cls, jdict):
        assert isinstance(jdict, dict)
        for sc in cls.__subclasses:
            result = sc.parse_this(jdict)
            if result is not None:
                return result
        raise ValueError("unexpected filter: {}".format(json.dumps(jdict)))

    @classmethod
    def parse_this(cls, jdict):
        raise NotImplementedError(cls.__name__)

    def to_jdict(self):
        raise NotImplementedError(self.__class__.__name__)

    def to_string(self):
        return json.dumps(self.to_jdict())

    @property
    def key(self):
        return self.to_string()


@ExtraFilter.register
class RedisStoredFilter(ExtraFilter):

    def __init__(self, sid):
        self.sid = str(sid)

    @classmethod
    def parse_this(cls, jdict):
        if jdict.get('type') == 't1':
            return RedisStoredFilter(jdict['sid'])

    def to_jdict(self):
        return {'type': 't1', 'sid': self.sid}


@ExtraFilter.register
class MysqlStoredFilter(ExtraFilter):

    def __init__(self, id_):
        self.id = int(id_)

    @classmethod
    def parse_this(cls, jdict):
        if jdict.get('type') == 't2':
            return MysqlStoredFilter(jdict['id'])

    def to_jdict(self):
        return {'type': 't2', 'id': self.id}


class ExtraFilterSet(object):
    """
    福利筛选器集合
    """

    def __init__(self):
        self.__extra_filters = []

    def add_extra_filter(self, extra_filter):
        assert isinstance(extra_filter, ExtraFilter)
        self.__extra_filters.append(extra_filter)

    def add_key_string(self, extra_filter_string):
        self.add_extra_filter(ExtraFilter.parse_string(extra_filter_string))

    def to_key_string_list(self):
        return [x.to_string() for x in self.__extra_filters]

    def add_key_string_list(self, string_list):
        for s in string_list:
            self.add_key_string(s)

    def make_query_inplace(self, filters):
        assert isinstance(filters, dict)

        special_id_list = []
        tip_name_list = []

        for ef in self.__extra_filters:
            if isinstance(ef, RedisStoredFilter):
                if ef.sid == 'popular':
                    filters['rating_gte'] = 4.0

                elif ef.sid == 'cashback':
                    filters['share_get_cashback'] = True

                elif ef.sid == 'floor':
                    filters['is_floor_price'] = True

                elif ef.sid == 'famous_doctor':
                    filters['famous_doctor'] = True

            elif isinstance(ef, MysqlStoredFilter):
                try:
                    sf = ServiceFilter.objects.get(pk=ef.id, is_online=True)
                    if sf.type == SERVICE_FILTER_TYPE.SPECIAL:
                        special_id_list.append(int(sf.value))

                    elif sf.type == SERVICE_FILTER_TYPE.TIP:
                        tip_name_list.append(sf.value)

                except ServiceFilter.DoesNotExist:
                    pass

            else:
                break

        if special_id_list:
            filters.setdefault('special_ids_and', []).extend(special_id_list)

        if tip_name_list:
            filters.setdefault('tip_list_and', []).extend(tip_name_list)


class ExtraFilterWithName(object):

    def __init__(self, extra_filter, name):
        assert isinstance(extra_filter, ExtraFilter)
        self.extra_filter = extra_filter
        self.name = name

    @property
    def key(self):
        return self.extra_filter.key

    @classmethod
    def get_all(cls, version):
        result = []
        for sf in ServiceFilter.objects.filter(is_online=True).order_by('ordering', 'id'):
            result.append(ExtraFilterWithName(
                extra_filter=MysqlStoredFilter(sf.id),
                name=sf.name,
            ))
        # 7.4.0后不再显示以下模块
        if LooseVersion(version) < LooseVersion('7.4.0'):
            for key, value in BasicServiceHomeFilter.get()['basic'].items():
                if value['visible']:
                    result.append(ExtraFilterWithName(
                        extra_filter=RedisStoredFilter(sid=key),
                        name=value['title'],
                    ))
        return result


def get_one_exterior(exteriors, city_id, region_id):
    # 排序专题外显
    # 城市 > 大区 > id
    # TODO 不可认为 exteriors 一定有数据
    # TODO 提升性能

    def exterior_key(e):
        return (
            e.cities.filter(id=city_id).exists(),
            e.regions.filter(id=region_id).exists(),
            e.id,
        )
    return sorted(exteriors, key=exterior_key, reverse=True)[0]


def specialexterior_aggregate_by_rank(exteriors, city_id, region_id):
    # 相同排序(rank值)的专题外显(exteriors)只取一个
    # 没有城市的的话不做 取一
    # 认为 专题外显 已按 rank 从小到大有序
    # TODO 可以不认为 exteriors 有序，ranks value 可以是 exterior 列表

    if not city_id or city_id in WORLD_AREA_TYPE:
        return exteriors

    ranks = {}
    for index, ext in enumerate(exteriors):
        ranks.setdefault(ext.rank, []).append(index)

    result = []
    for rank in sorted(ranks.keys()):
        start, end = ranks[rank][0], ranks[rank][-1]
        result.append(get_one_exterior(exteriors[start:end+1], city_id, region_id))
    return result
