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

import datetime
import json

from django.conf import settings
from django.contrib.auth.models import User
from django.utils import timezone
from django.db.models import Q
from gm_types.gaia import (
    HOMEPAGE_OPERATE_TYPE,
    SLIDE_POSITION,
    GADGET_PAGE_TYPE,
    SMALLIMAGE_TYPE,
    SLIDE_TYPE,
    WORLD_AREA_TYPE,
    SLIDE_LOCATION,
    SLIDE_USER_TYPE,
    SLIDE_PAYMENT_TYPE,
    TAB_TYPES_NEW,
)
from gm_types.gaia import HOMEPAGE_OPERATE_LOCATION as HL
from gm_types.doris import CARD_TYPE
from api.models.slide import Slide, Gadget, ButtonGadget, ZoneLayout, CommunityDeploy, IndextabConfig, HomepageOperate, \
    SlideToDisplaySite, DisplaySite
from api.models import IndexFunction
from api.models import SmallImage
from api.models import City, Province
from api.models import TabOperate, HomepageIcon, HomepageActivity, FestivalHomepageIcon
from api.tool.user_tool import get_user_from_context, get_user_level, get_user_and_payment_info
from api.tool.operate_tool import format_operate_query

from rpc.decorators import bind, bind_context, cache_page
from rpc.cache import slide_cache
from rpc.decorators import list_interface
from rpc.tool.error_code import gen, CODES
from statistic.tasks import add_diary_pv
from api.tool.slide_tab_tool import UserTokenCollection
from api.tool.user_tool import filter_user_nick_name
from api.tool.user_tool import is_new_user_local
from api.tool.get_query import get_query_by_usertype_and_location


@bind("api/slide/list")
@cache_page(120)
@list_interface(offset_name='offset', limit_name='limit', element_model=Slide)
def slide_list(position=SLIDE_POSITION.FIRST, offset=0, limit=10, slide_types=None, display_type=None):
    q = Q()
    if slide_types:
        q &= Q(slide_type__in=slide_types)
    if display_type is not None:
        slide_ids = list(SlideToDisplaySite.objects.filter(
            display_site__display_type=display_type).values_list('slide_id', flat=True))
        q &= Q(id__in=slide_ids)

    data = Slide.query(q, position=position, offset=offset, limit=limit)
    diary_ids = []
    slides = data['slides']
    for slide in slides:
        if slide['slide_type'] == SLIDE_TYPE.DIARY:
            diary_ids.append(slide['diary_id'])

    add_diary_pv.delay(diary_ids)
    return data


# TODO: 迁移至 talos 需要删除
def get_diary_info_for_index(diary_ids, user):
    # api/slide/city_list_diary_ad_v1  todo 7675 已迁移，可删  180502
    from rpc.tool.es_helpers import get_objects_from_queryset_and_pk_list
    from talos.models.diary import Diary
    from social import SocialInfo
    from api.tool.datetime_tool import get_humanize_datetime, get_timestamp_or_none
    from gm_types.gaia import AUTHOR_TYPE, MEMBERSHIP_LEVEL
    from api.tool.user_tool import get_portrait_by_user

    if not diary_ids:
        return []

    diaries = get_objects_from_queryset_and_pk_list(
        Diary.objects.all().prefetch_related("topics"),
        diary_ids,
    )
    result = []

    social_info = None
    if user:
        social_info = SocialInfo(uid=user.id)

    for diary in diaries:
        # TODO: move query out of this for
        diary_author = User.objects.get(pk=diary.user_id)
        diary_data = {
            'diary_id': diary.id,
            'date': get_humanize_datetime(diary.last_modified),
            'last_modified': get_timestamp_or_none(diary.last_modified),
            'title_style_type': diary.title_style_type,
            'view_num': diary.view_num,
            'reply_num': diary.reply_num,
            'vote_num': diary.vote_num,

            'author_type': AUTHOR_TYPE.USER,
            'city': u'中国',  # TODO: delete this
            'user_id': diary.user_id,
            'user_portrait': get_portrait_by_user(diary_author),
            'user_nickname': filter_user_nick_name(diary_author),
            'is_voted': diary.is_voted_by(user),
            'is_following': social_info and social_info.is_following_user(uid=diary.user_id) or False,
            'membership_level': diary_author.userextra and diary_author.userextra.membership_level or MEMBERSHIP_LEVEL.NORMAL,
            'author': {
                'vote_num_gained': diary_author.person.vote_count,
                'topic_num_posted': diary_author.person.topic_count,
            },
            'user_level': get_user_level(diary_author),
        }
        diary_data.update(diary.get_data_from_cache_for_index())  # todo 没有？
        diary_data.update(diary.video_cover())
        result.append(diary_data)
    return result


@bind_context('api/slide/city_list_diary_ad')
def diary_ad(ctx, city_id=None):
    # todo 用api/slide/city_list_diary_ad_v1 ,7675上线后可删
    user = get_user_from_context(ctx)
    q = Q(show_as_diary=True)
    offset = 0
    limit = 10
    position = SLIDE_POSITION.DIARY_LIST_BANNER
    return_ordering = False
    if city_id in WORLD_AREA_TYPE:
        query_region_slide = None
        query_city_slide = None
        query_no_city_slide = q
        data = Slide.slide_city_query(query_region_slide, query_city_slide, query_no_city_slide,
                                      position, offset, limit,
                                      return_ordering, user)
    elif city_id:
        query_region_slide = None
        region = None
        province_id = None
        if position == SLIDE_POSITION.FIRST or position == SLIDE_POSITION.DIARY_LIST_BANNER:
            try:
                city = City.objects.get(id=city_id)
                if getattr(city, 'province'):
                    region = city.province.region
                    province_id = city.province.id
                    if region:
                        query_region_slide = (
                            q & Q(showregion__region=region)
                        )
            except City.DoesNotExist:
                pass

        if province_id:
            # 选北京显示朝阳,选朝阳显示北京
            query = (
                Q(related_slide__city__province_id=city_id) |
                Q(related_slide__city=city_id) |
                Q(related_slide__city=province_id)
            )
            query_city_slide = q & query
        else:
            query = (
                Q(related_slide__city__province_id=city_id) |
                Q(related_slide__city=city_id)
            )
            query_city_slide = q & query

        query_no_city_slide = q & Q(related_slide__isnull=True, showregion__region__isnull=True)

        if region:
            query_city_slide &= ~Q(showregion__region=region)

        data = Slide.slide_city_query(query_region_slide, query_city_slide, query_no_city_slide,
                                      position, offset, limit,
                                      return_ordering, user)
    else:
        return []
    diary_ids = [s['diary_id'] for s in data['slides']]
    return get_diary_info_for_index(diary_ids, user)

@bind_context('api/slide/city_list_diary_ad_v1')
def diary_ad_v1(ctx, city_id=None):
    user = get_user_from_context(ctx)
    q = Q(show_as_diary=True)
    offset = 0
    limit = 10
    position = SLIDE_POSITION.DIARY_LIST_BANNER
    return_ordering = False
    if city_id in WORLD_AREA_TYPE:
        query_region_slide = None
        query_city_slide = None
        query_no_city_slide = q
        data = Slide.slide_city_query(query_region_slide, query_city_slide, query_no_city_slide,
                                      position, offset, limit,
                                      return_ordering, user)
    elif city_id:
        query_region_slide = None
        region = None
        province_id = None
        if position == SLIDE_POSITION.FIRST or position == SLIDE_POSITION.DIARY_LIST_BANNER:
            try:
                city = City.objects.get(id=city_id)
                if getattr(city, 'province'):
                    region = city.province.region
                    province_id = city.province.id
                    if region:
                        query_region_slide = (
                            q & Q(showregion__region=region)
                        )
            except City.DoesNotExist:
                pass

        if province_id:
            # 选北京显示朝阳,选朝阳显示北京
            query = (
                Q(related_slide__city__province_id=city_id) |
                Q(related_slide__city=city_id) |
                Q(related_slide__city=province_id)
            )
            query_city_slide = q & query
        else:
            query = (
                Q(related_slide__city__province_id=city_id) |
                Q(related_slide__city=city_id)
            )
            query_city_slide = q & query

        query_no_city_slide = q & Q(related_slide__isnull=True, showregion__region__isnull=True)

        if region:
            query_city_slide &= ~Q(showregion__region=region)

        data = Slide.slide_city_query(query_region_slide, query_city_slide, query_no_city_slide,
                                      position, offset, limit,
                                      return_ordering, user)
    else:
        return {'diary_ids': []}

    return {'diary_ids': [s['diary_id'] for s in data['slides']]}


def _get_user_token_slide(limit=10,
                          position=SLIDE_POSITION.FIRST,
                          slide_types=None,
                          city_id=None,
                          location=None,
                          user_type=SLIDE_USER_TYPE.ALL_USER,
                          payment_type=SLIDE_PAYMENT_TYPE.ALL_PAYMENT,
                          display_type=None
                          ):
    if not Slide.get_visible(position):
        return {'visible': False, 'slides': []}

    base_query = Q(show_as_diary=False, is_online=True)
    if slide_types:
        base_query &= Q(slide_type__in=slide_types)
    if location:
        base_query &= Q(location=location)
    if position:
        base_query &= Q(position=position)
    if display_type is not None:
        slide_ids = list(SlideToDisplaySite.objects.filter(
            display_site__display_type=display_type).values_list('slide_id', flat=True))
        base_query &= Q(id__in=slide_ids)

    region, country_id = (None, None)
    try:
        city = City.objects.get(id=city_id)
        if city.province_id:
            province = Province.objects.select_related('region').get(id=city.province_id)
            region = province.region
            country_id = province.country_id
    except City.DoesNotExist:
        pass
    # 规则如下：
    # 1. 定位在全部地区、无定位、定位在海外，只能看到全部地区的banner(不能看到配置具体城市的banner)
    # 2. 定位在具体城市，可以看到该城市、大区、全部地区的banner
    if not city_id or city_id in WORLD_AREA_TYPE or (region and region.english_name == 'haiwai') or \
            (country_id and country_id != 'china'):
        city_query = Q(related_slide__isnull=True, showregion__region__isnull=True)
    else:
        city_query = Q(related_slide__city=city_id) | Q(related_slide__isnull=True, showregion__region__isnull=True)
        if region:
            city_query |= Q(showregion__region=region)

    now = timezone.now
    query = city_query & base_query
    query &= Q(effect_time__lte=now)
    query &= (Q(end_time__isnull=True) | Q(end_time__gte=now))
    raw_slides = Slide.objects.filter(query).order_by('ordering').distinct()

    # 获取当前用户类型和支付类型的slide, 优先级满足新用户且无支付>老用户且无支付>新用户>无支付>其他
    collect_banners = UserTokenCollection()
    collect_banners.add_bulk(list(raw_slides))
    collect_result = collect_banners.get_result((user_type, payment_type))

    # 获取带用户标记的banner的dict, token_group_banners = [{}, {}, ...]
    token_group_banners = [s for s in collect_result if s.get('token')]
    token_group_banners = sorted(token_group_banners, key=lambda y: y['ranking'])

    # 获取带用户标记的banner, token_banners = [slide1, slide2, ...]
    token_banners = []
    [token_banners.extend(x['data']) for x in token_group_banners]

    # 如果带用户标记的banner<limit, 从普通的banner中取剩下的部分
    normal_banners = []
    if not len(token_banners) >= limit:
        normal_group_banners = [s for s in collect_result if not s.get('token')]
        [normal_banners.extend(x['data']) for x in normal_group_banners]

    banners_detail = [x.slide_data() for x in (token_banners + normal_banners)]
    Slide.update_banner_diary_topic(banners_detail)

    result = {
        'slides': banners_detail,
        'visible': True
    }
    return result


def _get_previous_slide(ctx,
                        position=SLIDE_POSITION.FIRST,
                        offset=0,
                        limit=10,
                        slide_types=None,
                        city_id=None,
                        return_ordering=False,
                        with_offline=False,
                        location=None):
    """
    原接口slide_city_list抽出的子函数，除了新轮播图、大图横滑外，获取其他banner仍走该接口
    todo: 该接口待重构...
    :param ctx:
    :param position:
    :param offset:
    :param limit:
    :param slide_types:
    :param city_id:
    :param return_ordering:
    :param with_offline:
    :param location:
    :return:
    """
    user = get_user_from_context(ctx)
    q = Q(show_as_diary=False)
    if slide_types:
        q &= Q(slide_type__in=slide_types)

    if city_id in WORLD_AREA_TYPE:
        query_region_slide = None
        query_city_slide = None
        query_no_city_slide = q
        data = Slide.slide_city_query(query_region_slide, query_city_slide, query_no_city_slide,
                                      position, offset, limit,
                                      return_ordering, user, with_offline=with_offline, location=location)
    elif city_id:
        query_region_slide = None
        region = None
        city = None
        province_id = None
        if position in (SLIDE_POSITION.FIRST, SLIDE_POSITION.DIARY_LIST_BANNER, SLIDE_POSITION.STORY,
                        SLIDE_POSITION.SPECIAL):
            try:
                city = City.objects.get(id=city_id)
                if getattr(city, 'province'):
                    region = city.province.region
                    province_id = city.province.id
                    if region:
                        query_region_slide = (
                            q & Q(showregion__region=region)
                        )
            except City.DoesNotExist:
                pass

        if province_id:
            # 选北京显示朝阳,选朝阳显示北京
            query = (
                Q(related_slide__city__province_id=city_id) |
                Q(related_slide__city=city_id) |
                Q(related_slide__city=province_id)
            )
            query_city_slide = q & query
        else:
            query = (
                Q(related_slide__city__province_id=city_id) |
                Q(related_slide__city=city_id)
            )
            query_city_slide = q & query

        query_no_city_slide = q & Q(related_slide__isnull=True, showregion__region__isnull=True)

        if region:
            query_city_slide &= ~Q(showregion__region=region)

        data = Slide.slide_city_query(query_region_slide, query_city_slide, query_no_city_slide,
                                      position, offset, limit,
                                      return_ordering, user, with_offline=with_offline, location=location)
    else:
        # 兼容旧的
        data = Slide.query(q, position=position, offset=offset, limit=limit,
                           return_ordering=return_ordering, user=user, with_offline=with_offline)

    if return_ordering and data['slides']:
        result = []
        slides = data['slides']
        ordering = slides[0]['ordering']
        for slide in slides:
            i = slide['ordering']
            if result and i == ordering:
                if slide['banner_id'] > result[-1]['banner_id']:
                    result.pop()
                else:
                    continue
            result.append(slide)
            ordering = i
        data['slides'] = result

    return data


@bind_context("api/slide/city_list")
@list_interface(offset_name='offset', limit_name='limit', element_model=Slide)
def slide_city_list(ctx,
                    position=SLIDE_POSITION.FIRST,
                    offset=0,
                    limit=10,
                    slide_types=None,
                    city_id=None,
                    return_ordering=False,
                    with_offline=False,
                    location=None,
                    platform=None,
                    device_id=None,
                    display_type=None
                    ):
    # 获取首页轮播图、美购首页轮播图等banner
    if position in [SLIDE_POSITION.FIRST, SLIDE_POSITION.SERVICE_HOME, SLIDE_POSITION.SMALL]:
        user = get_user_from_context(ctx)

        params = {'platform': platform, 'device_id': device_id, 'user': user if user else None}
        user_payment_info = get_user_and_payment_info(**params)

        user_type = SLIDE_USER_TYPE.OLD_USER
        if user_payment_info and user_payment_info.get('is_new_user'):
            user_type = SLIDE_USER_TYPE.NEW_USER

        payment_type = SLIDE_PAYMENT_TYPE.HAVE_PAYMENT
        if user_payment_info and not user_payment_info.get('have_payment'):
            payment_type = SLIDE_PAYMENT_TYPE.NO_PAYMENT

        cache_key = "{}:{}:{}:{}:{}:{}:{}:{}".format(
            limit, position, slide_types, city_id, location, user_type, payment_type, display_type
        )
        data = slide_cache.get(cache_key)
        if data:
            return json.loads(data)

        result = _get_user_token_slide(limit=limit, position=position, slide_types=slide_types, city_id=city_id,
                                       location=location, user_type=user_type, payment_type=payment_type,
                                       display_type=display_type
                                       )

        if result.get("slides"):
            slide_cache.set(cache_key, json.dumps(result), ex=60 * 5)

    # 获取体验故事、日记本banner
    else:
        result = _get_previous_slide(ctx=ctx, position=position, offset=offset, limit=limit,
                                     slide_types=slide_types, city_id=city_id, return_ordering=return_ordering,
                                     with_offline=with_offline, location=location)

    # 增加日记本banner的浏览量
    diary_ids = [s['diary_id'] for s in result['slides'] if s['slide_type'] == SLIDE_TYPE.DIARY]
    add_diary_pv.delay(diary_ids)

    return result


@bind("api/slides")
@bind("api/slide/list_by_platform")
@cache_page(120)
def get_all_slides(platform=u'web'):
    """轮播图
       platform:
    """
    result = []
    if platform == u'web' or platform == u'mobile':
        slides = Slide.objects.filter(effect_time__lte=timezone.now, is_online=True)
        for slide in slides.order_by('ordering'):
            result.append(slide.slide_data())
    return result


@bind("api/slide/get")
def get(slide_id):
    try:
        slide = Slide.object.get(pk=slide_id)
        return slide.slide_data()
    except Slide.DoesNotExist:
        raise gen(CODES.SLIDE_NOT_FOUND)


@bind("api/slide/tab_list")
def get_tab_list():
    try:
        result = IndextabConfig.get()
    except:
        result = []

    return result


@bind('api/smallimage/lastest_n')
@cache_page(120)
@list_interface(limit_name='limit', element_model=SmallImage, element_func_list=[SmallImage.as_dict])
def smallimage(count=10):
    """
    首页小图
    :param count:
    :return:
    """
    sis = SmallImage.objects.filter(
        effect_time__lte=timezone.now).filter(
        is_online=True, type=SMALLIMAGE_TYPE.SMALLIMAGE)
    filter_end_time = Q(end_time__isnull=True) | Q(end_time__gte=timezone.now)
    sis = sis.filter(filter_end_time)
    sis = sis.order_by('ordering', "-created_time")
    return [si.as_dict() for si in sis[:count]]


@bind('api/gadget/get_index')
@cache_page(120)
def get_index_layout(city_id=None):
    res = {}

    #  轮播图 沿用原来的 api/slide/list接口
    res['buttons'] = ButtonGadget.get_buttons(page_type=GADGET_PAGE_TYPE.INDEX,
                                              mask_invisible=True)  # 按钮区
    res['slip_slides'] = SmallImage.get_slip_slides()  # 单排横划区
    if city_id:
        res['gadgets'] = Gadget.get_gadgets(page_type=GADGET_PAGE_TYPE.INDEX, city_id=city_id)  # 固定模板区
    else:
        res['gadgets'] = Gadget.get_gadgets(page_type=GADGET_PAGE_TYPE.INDEX)

    return res


@bind('api/gadget/get_servicehome')
@cache_page(120)
def get_servicehome_layout(city=None):
    #  轮播图 用 api/slide/list接口
    res = {}
    res['gadgets'] = Gadget.get_gadgets(page_type=GADGET_PAGE_TYPE.SERVICE_HOME, city_id=city)  # 固定模板区

    return res


@bind('api/gadget/get_communityhome')
@cache_page(120)
def get_communityhome_layout():
    res = {}
    res['buttons'] = ButtonGadget.get_buttons(page_type=GADGET_PAGE_TYPE.COMMUNITY_HOME,
                                              mask_invisible=True)  # 按钮区
    res['gadgets'] = Gadget.get_gadgets(page_type=GADGET_PAGE_TYPE.COMMUNITY_HOME)  # 固定模板区
    hot_tags = ZoneLayout.get_zone_layout()
    res['hot_tags'] = {
        'visible': hot_tags['zone_visible'],
        'hot_in_24hours': hot_tags['hot_in_24hours'],
    }
    community_deploy = CommunityDeploy.get_community_deploy()
    res['community_deploy'] = community_deploy
    return res


@bind('api/slide/get_related_type_info')
@cache_page(120)
def get_related_type_info(banner_id):
    # 首页精选中banner中的diary及topic点赞时，首先返回该banner中点赞对应的具体diary或topic
    try:
        _s = Slide.objects.get(pk=banner_id)
        if _s.topic_id:
            return {
                'vote_to': 'topic',
                'id': _s.topic_id,
            }
        elif _s.diary_id:
            return {
                'vote_to': 'diary',
                'id': _s.diary_id,
            }

        gen(CODES.OPERATION_NOT_SUPPORTED)
    except Slide.DoesNotExist:
        raise gen(CODES.SLIDE_NOT_FOUND)


@bind('api/slide/big_image_slider')
@cache_page(120)
def get_big_image_slider(start_num, count, location=SLIDE_LOCATION.FIRST):
    """
    todo: 等待策略改动，修改取大图横滑的规则
    :param start_num:
    :param count:
    :param location:
    :return:
    """
    slides = []

    queryset = Slide.objects.filter(location=location)[start_num: start_num + count]
    for slide in queryset:
        slides.append({
            'name': slide.title,
            'icon': slide.slide_img,
            'url': slide.url
        })
    return slides


@bind('api/index/v6/templates')
@cache_page(120)
def get_index_templates(city_id=None, platform=None, device_id=None, user_id=None):
    """
    新版首页的固定模版
    :param city_id:
    :return:
    """
    filter = {'page_type': GADGET_PAGE_TYPE.INDEX, 'city_id': city_id, 'show_in_v6': True}
    try:
        user = User.objects.get(id=user_id)
    except User.DoesNotExist:
        user = None
    user_type = SLIDE_USER_TYPE.NEW_USER if is_new_user_local(user, platform=platform, device_id=device_id)['is_new_user'] else SLIDE_USER_TYPE.OLD_USER
    filter['user_type'] = user_type
    return Gadget.get_gadgets(**filter)  # 固定模板区


def _format_homepage_operate_query(ctx, city_id=None, platform=None, device_id=None):
    user = get_user_from_context(ctx)
    return format_operate_query(user=user, city_id=city_id, platform=platform, device_id=device_id)


@bind_context('api/homepage/operate_banner')
def get_homepage_operate_banner(ctx, location, count=5, city_id=None, platform=None, device_id=None):
    params = {
        'ctx': ctx,
        'city_id': city_id,
        'platform': platform,
        'device_id': device_id
    }
    base_query = _format_homepage_operate_query(**params)
    base_query_set = HomepageOperate.objects.filter(base_query).order_by('rank', '-id')

    if isinstance(location, list):
        operate_banner_a = list(base_query_set.filter(location=HL.OPERATE_A)[:count])
        operate_banner_b = base_query_set.filter(location=HL.OPERATE_B).first()
        queryset = operate_banner_a
        if operate_banner_b:
            queryset.append(operate_banner_b)
    else:
        queryset = base_query_set.filter(location=location)[:count]

    result = [banner.banner_data() for banner in queryset]
    return filter(lambda r: r['entity_id'] is not None, result)


# 置顶配置位规则
_tab_map = {
    TAB_TYPES_NEW.GOSSIP: [CARD_TYPE.QUESTION, CARD_TYPE.ANSWER],
    TAB_TYPES_NEW.BIG_SHOT: [CARD_TYPE.QUESTION, CARD_TYPE.ANSWER],
    TAB_TYPES_NEW.HOME_VIDEO: [CARD_TYPE.DIARY],
    TAB_TYPES_NEW.CHOICE: [CARD_TYPE.DIARY, CARD_TYPE.ARTICLE, CARD_TYPE.ANSWER, CARD_TYPE.QUESTION],
}

@bind('api/homepage/operate_tab')
@cache_page(60 * 5)
def get_homepage_operate_tag(tab_type):
    top_num = 1 if tab_type == TAB_TYPES_NEW.CHOICE else 2
    objs = TabOperate.objects.filter(tab=tab_type,
                                     is_online=True,
                                     card_type__in=_tab_map[tab_type]
                                     ).order_by('rank', '-id')
    result = {}
    for rank, obj in enumerate(objs[:top_num]):
        if not result.get(obj.card_type):
            result[obj.card_type] = []
        result[obj.card_type].append((obj.card_id, rank))
    return result


@bind_context('api/homepage/icon')
def get_homepage_icon(ctx, city_id=None, platform=None, device_id=None, polymer_ids=[]):
    """

    :param ctx:
    :param city_id:
    :param platform:
    :param device_id:
    :param polymer_ids: 策略给出的自动排序后的品类聚合页id
    :return:
    """
    polymer_ids = [str(id) for id in polymer_ids]
    AUTO_RANK_NUM_FLAG = 999999
    user = get_user_from_context(ctx)
    params = {
            'user': user,
            'city_id': city_id,
            'platform': platform,
            'device_id': device_id
        }
    background = {"background_img": "", "font_color": "1"}

    # 筛选出用户可以看到的所有的icon， 可以保证包含了策略给出的icon id。
    query = get_query_by_usertype_and_location(**params)
    icons = list(HomepageIcon.objects.filter(query).order_by('rank', '-id'))

    # 筛选出可以使用的自动排序icon
    auto_icons = [
        item
        for item in icons
        if item.rank == AUTO_RANK_NUM_FLAG and item.jump_type == HOMEPAGE_OPERATE_TYPE.CATEGORY and item.jump in polymer_ids
    ]

    def sort_func(x):
        # 按照polymer_ids顺序排序，
        if x in polymer_ids:
            return polymer_ids.index(x)
        else:
            return len(polymer_ids)
    # auto_icons 为可用的补位icon
    auto_icons = sorted(auto_icons, key=lambda k: sort_func(k.jump))

    # 筛选出后台配置的icon 并且根据rank去重，保留id最大的icon, 自动排序icon不去重, 这里要注意策略提供的数据与后台不是时时同步的。
    backend_config_icons = [icons[0]]  # 如果后台没有配置固定位置icon ，则icons[0] 是用可能和auto_icons重复
    for icon in icons[1:]:
        if (icon.rank != backend_config_icons[-1].rank or icon.rank == AUTO_RANK_NUM_FLAG) and icon not in auto_icons:
            backend_config_icons.append(icon)
    if backend_config_icons[0] in auto_icons:
        backend_config_icons.remove(backend_config_icons[0])

    for icon in backend_config_icons:  # 到这里icons与auto_icons不会有重复
        auto_icons.insert(icon.rank - 1, icon)

    icon_result = [icon.icon_data() for icon in auto_icons[:settings.HOMEPAGE_ICON_CNT]]
    festival_img = FestivalHomepageIcon.objects.filter(query).order_by('-id').first()

    if festival_img:
        for index, value in enumerate(icon_result[:10]):
            if festival_img.img_data()['festival_img'][index]:
                icon_result[index]['image'] = festival_img.img_data()['festival_img'][index]
        background = {
            "background_img": festival_img.img_data()['background_img'],
            "font_color": festival_img.img_data()['font_color'],
        }
    return {"homepage_icon": icon_result, "index_background": background}


@bind_context('api/homepage/activity')
def get_homepage_activity(ctx, city_id=None, platform=None, device_id=None):
    user = get_user_from_context(ctx)
    params = {
        'user': user,
        'city_id': city_id,
        'platform': platform,
        'device_id': device_id
    }
    query = get_query_by_usertype_and_location(**params)
    activity = HomepageActivity.objects.filter(query).order_by('-id').first()
    if activity:
        activity = activity.data()
    else:
        activity = {
            "icon_image": "",
            "jump_type": "",
            "jump": "",
        }
    return {"homepage_activity": activity}
