# coding=utf-8

from __future__ import unicode_literals, print_function, absolute_import

import json
import copy
from operator import itemgetter


from django.conf import settings

from agile.models.tag import TagV3Relation
from api.models import Country, TagV3
from api.models import Province
from api.models import City
from api.models import Tag
from api.models import TAG_TYPE
from api.models import Campaign
from api.models import Doctor, Hospital
from gm_types.gaia import CAMPAIGN_MODULE, TAG_V3_TYPE
from rpc.cache import page_cache
from rpc.cache import make_cache_key
from api.tool.service_tool import get_special_services
from api.tool.itemwiki_tool import ItemwikiHot
from api.tool.city_tool import get_ares_cache

from api.manager.tag_manager import get_bodypart_tags, get_bodypart_new_tags
from search.utils.service import filter_service


COMMON_AREA_CACHE_KEY = 'common:filter:area'
COMMON_AREA_CACHE_KEY_V1 = 'common-filter-area-v1'
COMMON_AREA_CACHE_KEY_V2 = 'common-filter-area-v2'
COMMON_AREA_CACHE_KEY_V3 = 'common-filter-area-v3'
FILTER_AREA_CACHE_KEY_V1 = 'filter-area-v1'
COMMON_TAG_CACHE_KEY = 'common:with_hot:{}:with_level_3:{}:tag'
COMMON_TAG_V3_CACHE_KEY = 'common:with_hot:{}:with_level_3:{}:tag_v3'
SERVICE_AREA_CACHE_KEY = 'service:filters:area'
SERVICE_AREA_CACHE_KEY_V1 = 'service-filters-area-v1'
SERVICE_AREA_CACHE_KEY_V2 = 'service-filters-area-v2'  # 7690
SERVICE_TAG_CACHE_KEY = 'service:filter:tag'
SERVICE_NEW_TAG_CACHE_KEY = 'service:filter:tagv3-v1'
DOCTOR_AREA_CACHE_KEY = 'doctor:filters:area'
DOCTOR_AREA_CACHE_KEY_V1 = 'doctor-filters-area-v1'
DOCTOR_AREA_CACHE_KEY_V2 = 'doctor-filters-area-v2'
DOCTOR_AREA_CACHE_KEY_V3 = 'doctor-filters-area-v3'


def generate_areas_list(cities_ids):
    cities = City.objects.filter(id__in=cities_ids).select_related('province__tag', 'province__country__tag')
    data = {}

    def check_add_country_province_data(country, province):
        if country.id not in data:
            data[country.id] = {
                'country_name': country.name,
                'country_id': country.id,
                'tag_id': country.tag.id,
                'provinces': {},
            }
        province = city.province
        if province.id not in data[country.id]['provinces']:
            data[country.id]['provinces'][province.id] = province.province_data()
            data[country.id]['provinces'][province.id]['cities'] = []

    for city in cities:
        country = city.province.country
        province = city.province
        check_add_country_province_data(country, province)
        data[country.id]['provinces'][province.id]['cities'].append(city.city_data())

    result = []
    for country_id in sorted(data.keys(), key=lambda x: x.lower()):
        country_info = data[country_id]
        _country = {
            'name': country_info['country_name'],
            'id': country_info['country_id'],
            'tag_id': country_info['tag_id'],
            'provinces': [],
        }
        for province_id in country_info['provinces'].keys():
            province_info = country_info['provinces'][province_id]
            _country['provinces'].append(province_info)
        result.append(_country)

    # 省份和城市按照拼音字母顺序
    for country in result:
        country['provinces'] = sorted(country['provinces'], key=lambda x: x['id'])
        for province in country['provinces']:
            province['cities'] = sorted(province['cities'], key=lambda x: x['id'])

    return {'country': result}


def _filter_condition_city(cities):
    return lambda x: x['id'] in cities


def generate_areas_list_v1(cities=None, exclude_gat=False):

    key = get_predicate(cities)
    cache = get_ares_cache(exclude_gat=exclude_gat)

    data = []
    for country in cache['countries']:
        for group in country.get('groups', []):
            group['cities'] = filter(key, group['cities'])
        country['groups'] = filter(lambda x: x['cities'], country['groups'])
        data.append(country)

    return data


def filter_setting_cities(setting_cities, country):
    """设置中的城市列表根据数据库添加tag_id。

    :param setting_cities: 设置中的城市列表
    :param country: 数据库中的城市列表，有tag_id
    :return:
    """
    ret = []
    for sc in setting_cities:
        next_city = False
        for group in country.get('groups', []):
            for city in group.get('cities', []):
                if sc["id"] == city["id"]:
                    sc["tag_id"] = city["tag_id"]
                    ret.append(sc)
                    next_city = True
                    break
            if next_city:
                break

    return ret


def generate_areas_list_v2(cities=None, exclude_gat=True):
    # 7690 修改点：将港澳台移出中国，归结到"海外/港澳台",添加热门城市

    key = get_predicate(cities)
    cache = get_ares_cache(exclude_gat=exclude_gat)

    data = []
    for country in cache['countries']:

        for group in country.get('groups', []):
            group['cities'] = filter(key, group['cities'])
        country['groups'] = filter(lambda x: x['cities'], country['groups'])

        if country['name'] == '中国':
            hot_cities = filter_setting_cities(settings.HOT_CITIES, country)
        else:
            hot_cities = filter_setting_cities(settings.FOREIGN_HOT_CITIES, country)

        if country['groups']:
            country['groups'].insert(0, {
                "is_hot": True,
                "initial": "热",
                "cities": filter(key, hot_cities),
                "title": "热门城市"
            })

        data.append(country)

    return data


def get_predicate(cities):
    """过滤器，仅针对当前城市进行筛选。"""

    if cities is None:
        key = itemgetter('id')
    else:
        cities = frozenset(cities)
        key = _filter_condition_city(cities)

    return key


def generate_tags(tag_ids, ordering=False):
    """
    在tag列表中挑选二级tag组成筛选器要用的数据
    1. tag列表中获取二级tag列表
    2. tag列表中获取三级tag,如果三级tag的父tag(二级tag)不在第一步获取的列表中,补充进去
    3. 拿到一级tag列表,遍历一级下的二级列表,判断二级tag是否在之前生成的列表中,如果不在就丢弃
    """
    tag_ids = set(tag_ids)
    tag_ids = filter(bool, tag_ids)  # 去除None
    tags = Tag.objects.filter(id__in=tag_ids)

    second_tags = tags.filter(tag_type=TAG_TYPE.BODY_PART_SUB_ITEM, is_online=True)
    second_tags_id = list(set(second_tags.values_list('id', flat=True)))

    # 如果美购中有三级的tag 将三级对应的二级tag添加到筛选器列表
    third_tags = tags.filter(tag_type=TAG_TYPE.ITEM_WIKI)
    if third_tags:
        for _tag in third_tags:
            parent_tag = _tag.parent_tags()
            if not parent_tag:
                continue
            for _parent_tag in parent_tag:
                if _parent_tag.tag_type != TAG_TYPE.BODY_PART_SUB_ITEM:
                    continue
                elif _parent_tag.id not in second_tags_id and _parent_tag.is_online:
                    second_tags_id.append(_parent_tag.id)

    if not second_tags_id:
        return []

    result = []
    if ordering:
        first_tags = Tag.objects.filter(tag_type=TAG_TYPE.BODY_PART, is_online=True).order_by('ordering', 'id')
    else:
        first_tags = Tag.objects.filter(tag_type=TAG_TYPE.BODY_PART, is_online=True)
    for tag in first_tags:
        t = {'name': tag.name, 'tag_id': tag.id, 'subtags': []}
        child_tags = tag.child_tags_with_condition_is_online(True, ordering=ordering)
        for _tag in child_tags:
            if _tag.id not in second_tags_id:
                continue
            t['subtags'].append({
                'name': _tag.name,
                'tag_id': _tag.id,
                'subtags': [],
            })
        if not t['subtags']:
            continue
        result.append(t)
    return result


def generate_new_tags(tag_ids, ordering=False):
    """
    在新tag列表中挑选二级tag组成筛选器要用的数据
    1. 新tag列表中获取二级tag列表
    2. 新tag列表中获取三级tag,如果三级tag的父tag(二级tag)不在第一步获取的列表中,补充进去
    3. 拿到一级tag列表,遍历一级下的二级列表,判断二级tag是否在之前生成的列表中,如果不在就丢弃
    """
    tag_ids = set(tag_ids)
    tag_ids = filter(bool, tag_ids)  # 去除None
    tags = TagV3.objects.filter(id__in=tag_ids)

    second_tags = tags.filter(tag_type=TAG_V3_TYPE.SECOND_CLASSIFY, is_online=True, is_display=True)
    second_tags_id = list(set(second_tags.values_list('id', flat=True)))

    # 如果美购中有三级的tag 将三级对应的二级tag添加到筛选器列表
    third_tags = tags.filter(tag_type=TAG_V3_TYPE.NORMAL, is_display=True)
    if third_tags:
        for _tag in third_tags:
            parents_relations = TagV3Relation.objects.filter(child=_tag, is_online=True, parent__is_display=True)
            if not parents_relations:
                parent_tag = []
            else:
                parents = [r.parent for r in parents_relations]
                parent_tag = parents
            # parent_tag = _tag.parents_relations()
            if not parent_tag:
                continue
            for _parent_tag in parent_tag:
                if _parent_tag.tag_type != TAG_V3_TYPE.SECOND_CLASSIFY:
                    continue
                elif _parent_tag.id not in second_tags_id and _parent_tag.is_online and _parent_tag.is_display:
                    second_tags_id.append(_parent_tag.id)

    if not second_tags_id:
        return []

    result = []
    first_tags = TagV3.objects.filter(tag_type=TAG_V3_TYPE.FIRST_CLASSIFY, is_online=True, is_display=True)
    for tag in first_tags:
        t = {'name': tag.name, 'tag_id': tag.id, 'subtags': []}
        child_tags = tag.child_new_tags_with_condition_is_online(True, ordering=ordering)
        for _tag in child_tags:
            if _tag.id not in second_tags_id:
                continue
            t['subtags'].append({
                'name': _tag.name,
                'tag_id': _tag.id,
                'subtags': [],
            })
        if not t['subtags']:
            continue
        result.append(t)
    return result


def generate_area_filter_by_service(services):
    cities_ids = services.values_list('doctor__hospital__city', flat=True)
    return generate_areas_list(cities_ids)


def generate_service_area_filter(qs, exclude_gat=False):
    cities = qs.values_list('doctor__hospital__city', flat=True)
    return generate_areas_list_v1(cities, exclude_gat=exclude_gat)


def generate_service_area_filter_v2(qs):
    doctor_ids = set(qs.values_list("doctor_id", flat=True))
    hospital_ids = set(Doctor.objects.filter(id__in=doctor_ids).values_list("hospital_id", flat=True))
    cities = set(Hospital.objects.filter(id__in=hospital_ids).values_list("city_id", flat=True))
    return generate_areas_list_v2(cities)


def generate_area_filter_by_doctors(doctors):
    # provinces_ids = doctors.values_list('hospital__city__province', flat=True)
    cities_ids = doctors.values_list('hospital__city', flat=True)
    return generate_areas_list(cities_ids)


def generate_doctor_area_filter(qs):
    cities = qs.values_list('hospital__city', flat=True)
    return generate_areas_list_v1(cities)


def generate_doctor_area_filter_v2(qs):
    cities = qs.values_list('hospital__city', flat=True)
    return generate_areas_list_v2(cities)


def generate_tag_filter_by_service(services, ordering=False):
    tag_ids = set(services.values_list('tags', flat=True))
    return generate_tags(tag_ids, ordering=ordering)

def generate_new_tag_filter_by_service(services, ordering=False):
    tag_ids = set(services.values_list('new_tags', flat=True))
    return generate_new_tags(tag_ids, ordering=ordering)


def get_all_tags(with_hot=True, with_level_3=False):
    tags = []

    if with_hot:
        hot_items = ItemwikiHot.get_objs()
        hot_data = {
            'name': u'热门',
            'subtags': []
           }
        for item in hot_items:
            hot_data['subtags'].append(item.wiki_data())
        tags.append(hot_data)

    bodypart_tags = get_bodypart_tags(with_level_3=with_level_3)
    tags.extend(bodypart_tags)

    return {'tags': tags}


def get_all_new_tags(with_hot=True, with_level_3=False, child_types=[]):
    tags = []

    bodypart_tags = get_bodypart_new_tags(with_level_3=with_level_3, child_types=child_types)
    tags.extend(bodypart_tags)

    return {'new_tags': tags}


def get_all_areas():
    countries = Country.objects.all()
    show_countries = []
    for country in countries:
        try:
            tag = country.tag
            if filter_service(size=1, filters={'area_tag_id': tag.id}):
                show_countries.append(country.data())
        except:
            pass
    return {'country': show_countries}


def get_all_areas_v1(cities=None, exclude_gat=False):
    return generate_areas_list_v1(cities=cities, exclude_gat=exclude_gat)


def get_all_areas_v2(cities=None, exclude_gat=False):
    return generate_areas_list_v2(cities=cities, exclude_gat=exclude_gat)


def build_special_tag_filter(special_id=None):
    cache_key = make_cache_key(build_special_tag_filter, special_id=special_id)
    if not special_id or not isinstance(special_id, (int, long)):
        tags = get_all_tags(with_hot=False)['tags']
    else:
        services = get_special_services(special_id=special_id)
        if not services:
            tags = get_all_tags(with_hot=False)['tags']
        else:
            tags = generate_tag_filter_by_service(services)
    page_cache.set(cache_key, json.dumps(tags))
    return tags

def build_special_new_tag_filter(special_id=None):
    cache_key = make_cache_key(build_special_new_tag_filter, special_id=special_id)
    if not special_id or not isinstance(special_id, (int, long)):
        new_tags = get_all_new_tags(with_hot=False)['new_tags']
    else:
        services = get_special_services(special_id=special_id)
        if not services:
            new_tags = get_all_new_tags(with_hot=False)['new_tags']
        else:
            new_tags = generate_new_tag_filter_by_service(services)
    page_cache.set(cache_key, json.dumps(new_tags), ex=60*60*24)
    return new_tags


def build_special_area_filter(special_id=None, exclude_gat=False):
    cache_key = make_cache_key(build_special_area_filter, special_id=special_id) + '-v1'
    if not special_id or not isinstance(special_id, (int, long)):
        areas = get_all_areas_v2(exclude_gat=exclude_gat)
    else:
        services = get_special_services(special_id=special_id)
        if not services:
            areas = get_all_areas_v2(exclude_gat=exclude_gat)
        else:
            areas = generate_service_area_filter_v2(services)
    page_cache.set(cache_key, json.dumps(areas))
    return areas


def campaign_to_special(campaign_id):
    try:
        campaign = Campaign.objects.get(pk=campaign_id)
        specials = campaign.campaignlayout_set.filter(module=CAMPAIGN_MODULE.OVERFLOW)
        special_id = int(specials[0].related)
    except:
        special_id = campaign_id
    return special_id


def generate_visual_tags(tag_ids):
    """
    可视化获取老标签树形结构
    只返回一级二级标签
    """
    tag_ids = set(tag_ids)
    tag_ids = filter(bool, tag_ids)  # 去除None
    tags = Tag.objects.filter(id__in=tag_ids)

    second_tags = tags.filter(tag_type=TAG_TYPE.BODY_PART_SUB_ITEM, is_online=True)
    second_tags_id = list(set(second_tags.values_list('id', flat=True)))

    # 如果美购中有三级的tag 将三级对应的二级tag添加到筛选器列表
    third_tags = tags.filter(tag_type=TAG_TYPE.ITEM_WIKI)
    if third_tags:
        for _tag in third_tags:
            parent_tag = _tag.parent_tags()
            if not parent_tag:
                continue
            for _parent_tag in parent_tag:
                if _parent_tag.tag_type != TAG_TYPE.BODY_PART_SUB_ITEM:
                    continue
                elif _parent_tag.id not in second_tags_id and _parent_tag.is_online:
                    second_tags_id.append(_parent_tag.id)

    result = []
    all_first_tags = Tag.objects.filter(tag_type=TAG_TYPE.BODY_PART, is_online=True)
    for tag in all_first_tags:
        t = {'name': tag.name, 'tag_id': tag.id, 'subtags': []}
        child_tags = tag.child_tags_with_condition_is_online(True)
        for _tag in child_tags:
            if tag.id not in tag_ids and _tag.id not in second_tags_id:
                continue
            t['subtags'].append({
                'name': _tag.name,
                'tag_id': _tag.id,
                'subtags': [],
            })
        if not t['subtags']:
            continue
        result.append(t)
    return result
