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

import json
import time
import threading
from datetime import datetime, timedelta

from django.db import models
from django.db.models import Q
from django.utils import timezone
from gm_serializer import fields as gm_fields
from gm_types.gaia import (
    GADGET_PAGE_TYPE,
    GADGET_TEMPLATE_TYPE,
    SMALLIMAGE_TYPE,
    SLIDE_TYPE,
    WORLD_AREA_TYPE,
    SLIDE_SERVICE_TYPE,
    SLIDE_LOCATION,
    SLIDE_USER_TYPE,
    SLIDE_PAYMENT_TYPE,
    HOMEPAGE_OPERATE_TYPE,
    HOMEPAGE_OPERATE_LOCATION,
    TAB_TYPES_NEW,
    INDEX_CARD_TYPE,
    DISPLAY_SITE,
    FONT_COLOR,
    FEED_SERVICE_TYPE,
    FEED_SHOW_TYPE,
    TAB_INDEX_CLASSIFY,
    HOME_PAGE_ICON_VERSION,
    TAB_OPERATE_VERSION,
    FEED_OPERATE_VERSION,
    GADGET_VERSION,
    SLIDE_VERSION,
    FESTIVAL_HOMEPAGE_ICON_VERSION,
    FEED_TAB_TYPE,
    Event_Type, SOURCE_POSITION_DEVICE_TYPE, PLATFORM_CHOICES)
from gm_types.doris import CARD_TYPE

from gm_upload import IMG_TYPE, ImgUrlField

from rpc.cache import gadget_cache, index_tab_cache
from rpc.tool.dict_mixin import to_dict
from api.basemodel import RequestSourceModel

from .area import City, Region
from .bodypart import BodyPart
from .service import Service
from .special import Special, SeckillPolymer
from .tag import Tag
from .types import SLIDE_POSITION, SLIDE_LAYOUT
from .user import User
from api.tool.user_tool import get_portrait_by_user_id, get_user_level, get_user_by_id
from rpc.all import get_rpc_remote_invoker

# TODO: TALOS MIGRATE
from talos.models.live import ZhiboConfig


class QuestionManager(object):
    def __call__(self, pk_list):
        return get_rpc_remote_invoker()['qa/foreignkey/question'](question_ids=pk_list).unwrap()


class AnswerManager(object):
    def __call__(self, pk_list):
        return get_rpc_remote_invoker()['qa/foreignkey/answer'](answer_ids=pk_list).unwrap()


class DisplaySite(models.Model):
    """
    轮播图的展示位置 如 PC站、M站、小程序...
    """
    class Meta:
        verbose_name = u'轮播图展示位置'
        verbose_name_plural = u'轮播图展示位置'
        app_label = 'api'
    display_type = models.IntegerField(verbose_name='展示位置', choices=DISPLAY_SITE, default=DISPLAY_SITE.APP)
    slide = models.ManyToManyField('Slide', verbose_name='关联的轮播图', null=True, blank=True)


class SlideToDisplaySite(models.Model):
    class Meta:
        verbose_name = 'ManyToMany Relationship'
        app_label = 'api'
    slide = models.ForeignKey('Slide', verbose_name='轮播图')
    display_site = models.ForeignKey(DisplaySite, verbose_name='展示位置')


class Slide(RequestSourceModel):
    RKEY_VISIBLE = 'slide_visible'  # redis存储轮播图是否显示的key

    class Meta:
        verbose_name = u'轮播图'
        verbose_name_plural = u'轮播图'
        app_label = 'api'

    slide_type = models.CharField(max_length=2, choices=SLIDE_TYPE, default=SLIDE_TYPE.TOPIC, db_index=True,
                                  verbose_name=u'跳转的类型')
    service_type = models.CharField(max_length=1, choices=SLIDE_SERVICE_TYPE, default=SLIDE_SERVICE_TYPE.DEAL,
                                    verbose_name=u'业务类型')
    slide_layout = models.CharField(max_length=2, choices=SLIDE_LAYOUT, default=SLIDE_LAYOUT.CAROUSEL, db_index=True,
                                    verbose_name=u'轮播图布局')
    slide_img = ImgUrlField(img_type=IMG_TYPE.SLIDE, max_length=1024, null=False, blank=False,
                            verbose_name=u'图片地址320*640')
    new_slide_img = ImgUrlField(img_type=IMG_TYPE.SLIDE, max_length=1024, null=False, blank=False, default='',
                            verbose_name=u'配置2:1尺寸的图片')
    app_new_slide_img = ImgUrlField(img_type=IMG_TYPE.SLIDE, max_length=256, blank=False, default='',
                                verbose_name=u'app新尺寸(7770及以上版本')
    slide_banner_img = ImgUrlField(img_type=IMG_TYPE.SLIDE, max_length=1024, null=False, blank=False,
                                   verbose_name=u'图片地址1920*380')
    color = models.CharField(max_length=100, verbose_name=u'配置色号', null=True, blank=True)
    # 新的新版本图片
    slide_img_big = ImgUrlField(img_type=IMG_TYPE.SLIDE, max_length=1024, blank=False,
                                verbose_name=u'图片地址320*640')
    slide_img1 = ImgUrlField(img_type=IMG_TYPE.SLIDE, max_length=1024, null=True, blank=True, default='',
                             verbose_name=u'图片地址256*640')
    topic_id = models.IntegerField(verbose_name=u'指定的话题ID', null=True, blank=True)
    service = models.ForeignKey(Service, verbose_name=u'指定的服务', null=True, blank=True)
    diary_id = models.IntegerField(null=True, blank=True)
    zone_single = models.ForeignKey(BodyPart, verbose_name=u'指定的圈子', null=True, blank=True)
    url = models.CharField(max_length=1024, null=True, blank=True, verbose_name=u'跳转的网址')
    ordering = models.IntegerField(default=20, verbose_name=u"展示顺序", help_text=u"小的排在前，大的排在后")
    created_time = models.DateTimeField(auto_now_add=True, verbose_name=u'添加时间')
    effect_time = models.DateTimeField(null=True, verbose_name=u'生效时间', default=timezone.now)
    end_time = models.DateTimeField(null=True, verbose_name=u'下线时间', blank=True)
    is_online = models.BooleanField(default=True, help_text=u"是否上线", verbose_name=u"上线")
    tag = models.ForeignKey(Tag, verbose_name=u'指定的Tag列表', null=True, blank=True)
    special = models.ForeignKey(Special, verbose_name=u'指定的福利专题', null=True, blank=True)
    activity_id = models.IntegerField(null=True, blank=True)
    position = models.CharField(max_length=2, choices=SLIDE_POSITION, default=SLIDE_POSITION.FIRST,
                                verbose_name=u'展示页面(首页/日记本页/美购首页 etc.)',
                                help_text=u'请选择该轮播图展示在首页第几个位置')
    title = models.CharField(max_length=100, verbose_name=u'名称', null=True, blank=True)
    is_show_info = models.BooleanField(u'是否显示信息详细', default=False)

    waterfalls_pic = ImgUrlField(
        img_type=IMG_TYPE.SLIDE, max_length=1024, null=False, blank=False,
        verbose_name=u'瀑布流地址'
    )
    user = models.ForeignKey(User, verbose_name=u'指定的用户', null=True, blank=True)
    zhiboconfig_id = models.IntegerField(u'直播预告', null=True, blank=True)
    not_show_title = models.BooleanField(u'信息流中不显示描述', default=True)
    show_as_diary = models.BooleanField(verbose_name='以日记本形式展示', default=False)

    column_id = models.IntegerField(verbose_name=u'指定的专栏', null=True, blank=True)
    content_polymer_id = models.IntegerField(verbose_name=u'内容聚合页', null=True, blank=True)
    question = gm_fields.MagicField(type=int, manager=QuestionManager, db_column='question_id', ttl=60 * 5, null=True,
                                    blank=True)
    answer = gm_fields.MagicField(type=int, manager=AnswerManager, db_column='answer_id', ttl=60 * 5, null=True,
                                  blank=True)
    location = models.CharField(u'位置', max_length=2, choices=SLIDE_LOCATION, default=SLIDE_LOCATION.OLD)
    user_type = models.CharField(max_length=2, choices=SLIDE_USER_TYPE, default=SLIDE_USER_TYPE.ALL_USER)
    payment_type = models.CharField(max_length=2, choices=SLIDE_PAYMENT_TYPE, default=SLIDE_PAYMENT_TYPE.ALL_PAYMENT)
    new_seckill_id = models.IntegerField(verbose_name=u'新秒杀专场id', default=0)
    seckill_polymer_id = models.IntegerField(verbose_name=u'秒杀聚合id', default=0)
    visualpage_id = models.IntegerField(verbose_name=u'自定义专题页面id', default=0)
    version = models.CharField(verbose_name=u'版本号', max_length=2, choices=SLIDE_VERSION, default=SLIDE_VERSION.V1)
    promotion_id = models.IntegerField(verbose_name=u'促销活动id', null=True, db_index=True)
    event_type = models.CharField(verbose_name=u'专题类型', max_length=2, choices=Event_Type, default=Event_Type.Other)
    weight = models.IntegerField(verbose_name=u'出现权重', max_length=2, default=1)
    device_type = models.CharField(verbose_name=u'设备类型', max_length=2, choices=SOURCE_POSITION_DEVICE_TYPE.choices,
                                      default=SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE)

    def slide_data(self, return_ordering=False, user=None):
        # NOTE return_ordering 和 user 已废弃

        if self.slide_img1:
            slide_img = self.slide_img1
        elif self.slide_img:
            slide_img = self.slide_img
        else:
            slide_img = u''

        result = {
            'id': self.id,
            'slide_type': self.slide_type,  # 0 话题 1 指定网页 2 福利详情 3 我的积分 4 邀请好友 5 创建话题 6 福利列表
            'slide_img': slide_img,
            'new_slide_img': self.new_slide_img,  # 7710版本以后逐渐使用2：1比例的图片替换原有图片
            'app_new_slide_img': self.app_new_slide_img,
            'slide_img_big': self.slide_img_big,
            'topic_id': self.topic_id,
            'service_id': self.service_id if self.service_id else None,
            'diary_id': self.diary_id,
            'url': self.url if self.url else u'',
            'special_id': self.special_id if self.special_id else None,
            'is_new_special': self.special.is_new_special if self.special_id else None,
            'tag_id': self.tag_id if self.tag_id else None,
            'tag_name': self.tag.name if self.tag_id else None,
            'activity_id': self.activity_id,
            'title': '' if self.not_show_title and self.position in (SLIDE_POSITION.DIARY_LIST_BANNER,) else self.title,
            'live_channel_id': self.try_to_get_live_channel_id(
                ZhiboConfig.objects.get(pk=self.zhiboconfig_id).anchor_user_id) if self.zhiboconfig_id else None,
            'service_type': self.service_type,
            'pc_slide_img': self.slide_banner_img,
            'pc_slide_color': self.color,

            'column_id': self.column_id,
            'question_id': self.question_id,
            'content_polymer_id': self.content_polymer_id,
            'answer_id': self.answer_id,
            'ordering': self.ordering,
            'new_seckill_id': self.new_seckill_id,
            'seckill_polymer_id': self.seckill_polymer_id,
            'visualpage_id': self.visualpage_id,
            'weight': self.weight,
        }

        """1.
            修改为带上发帖用户头像、昵称；
            2.
            中间显示banner图片，并展现banner配置文案（允许不展现）；
            3.
            底部展现跳转页面的浏览数、评论数、赞数（对日记、帖子两种落地页进行支持，其它分类落地页隐藏三模块）
        """
        update_data = {
            'show_footer': False,
            'vote_num': 0,
            'reply_num': 0,
            'view_num': 0,
            'user_portrait': get_portrait_by_user_id(22),  # 所长大人
            'user_nickname': u'所长大人',
            'user_id': 22,
            'is_voted': False,
            # 用户等级权益，保证格式统一
            'user_level': {
                'level_icon': '',
                'membership_icon': '',
                'constellation_icon': '',
            },
            'user_token': True if (self.user_type == SLIDE_USER_TYPE.NEW_USER or
                                   self.payment_type == SLIDE_PAYMENT_TYPE.NO_PAYMENT) else False
        }

        result.update(update_data)
        return result

    def try_to_get_live_channel_id(self, user_id):
        from talos.models.live import LiveWhiteList, LiveChannel
        person_id = User.objects.get(pk=user_id).person.id.hex
        if LiveWhiteList.objects.filter(user_id=user_id).exists():
            channel = LiveChannel.objects.filter(person_id=person_id).first()
            if channel:
                return channel.id
            else:
                from api.tool.live_tool import get_or_create_channel_by_user_id
                return get_or_create_channel_by_user_id(user_id).id
        else:
            return 0

    @classmethod
    def query(cls, q, position, offset=0, limit=10,
              return_ordering=False, user=None, with_offline=False):
        """
        :param q:
        :param position: 轮播图展示页
        :param offset:
        :param limit:
        :param return_ordering: 是否返回排序字段
        :return:
        """
        visible = cls.get_visible(position)  # 先检查是否显示
        if not visible:
            return {
                'visible': False,
                'slides': []
            }

        slides = cls.slide_query(q, position, offset, limit, return_ordering, with_offline)
        data = {}
        items = []
        for slide in slides:
            items.append(slide.slide_data(return_ordering=return_ordering, user=user))
        data["slides"] = items
        data['visible'] = True
        return data

    @classmethod
    def update_banner_diary_topic(cls, items):
        """
        从原slide_city_query抽出的子函数
        :param items: [slide1, slide2,...]
        :return:
        """
        diary_ids = []
        topic_ids = []
        answer_ids = []
        for item in items:
            if item['slide_type'] == SLIDE_TYPE.DIARY:
                diary_ids.append(item['diary_id'])
            elif item['slide_type'] == SLIDE_TYPE.COLUMN_ARTICLE or item['slide_type'] == SLIDE_TYPE.TOPIC:
                topic_ids.append(item['topic_id'])
            elif item['slide_type'] == SLIDE_TYPE.ANSWER:
                answer_ids.append(item['answer_id'])

        diary_update, topic_update, answer_update = {}, {}, {}

        from api.tool.diary_tool import get_index_banner_diary_info_by_ids
        if diary_ids:
            diary_ids = sorted(list(set(diary_ids)))
            diary_update = get_index_banner_diary_info_by_ids(diary_ids=diary_ids)

        from api.tool.topic_tool import get_index_banner_topic_info_by_ids
        if topic_ids:
            topic_ids = sorted(list(set(topic_ids)))
            topic_update = get_index_banner_topic_info_by_ids(topic_ids=topic_ids)
            topic_update = {int(k): v for k, v in topic_update.items()}

        from api.tool.answer_tool import get_answer_list_by_ids
        if answer_ids:
            answer_update = get_answer_list_by_ids(answer_ids)

        for item in items:
            if item['slide_type'] == SLIDE_TYPE.DIARY and item['diary_id'] in diary_update:
                item.update(diary_update[item['diary_id']])
                item['user_level'] = get_user_level(get_user_by_id(item['user_id']))
                item.update({'show_footer': True})
            elif (item['slide_type'] == SLIDE_TYPE.COLUMN_ARTICLE or item['slide_type'] == SLIDE_TYPE.TOPIC) and item['topic_id'] in topic_update:
                item.update(topic_update[item['topic_id']])
                item['user_level'] = get_user_level(get_user_by_id(item['user_id']))
                item.update({'show_footer': True})
            elif item['slide_type'] == SLIDE_TYPE.ANSWER and item['answer_id'] in answer_update:
                related_answer = answer_update[item['answer_id']]
                related_answer.pop('title', None)
                item.update(related_answer)
                item['user_level'] = get_user_level(get_user_by_id(item['user_id']))
                item.update({'show_footer': True})

    @classmethod
    def slide_city_query(cls, query_region_slide, query_city_slide, query_no_city_slide, position,
                         offset, limit, return_ordering=False, user=None, with_offline=False, location=None):
        visible = Slide.get_visible(position)  # 先检查是否显示
        if not visible:
            return {
                'visible': False,
                'slides': []
            }

        if query_city_slide:
            city_slides = cls.slide_query(query_city_slide, position, offset, limit, return_ordering, with_offline,
                                          location)
        else:
            city_slides = []

        no_city_slides = cls.slide_query(query_no_city_slide, position, offset, limit, return_ordering, with_offline,
                                         location)

        if query_region_slide:
            region_slides = cls.slide_query(query_region_slide, position, offset, limit, return_ordering, with_offline,
                                            location)
        else:
            region_slides = []

        order_list = []
        # 优先级：大区＞城市＞空 ordering取的整数 +0.x 排优先级
        for slide in region_slides:
            order_list.append({"ordering": float(slide.ordering), "val": slide})

        for slide in city_slides:
            ordering = slide.ordering + 0.5
            order_list.append({"ordering": float(ordering), "val": slide})

        for slide in no_city_slides:
            ordering = slide.ordering + 0.6
            order_list.append({"ordering": float(ordering), "val": slide})

        order_list = sorted(order_list, key=lambda order_item: order_item['ordering'])
        data = {}
        items = []
        for item in order_list:
            slide = item['val']
            items.append(slide.slide_data(return_ordering=return_ordering, user=user))

        cls.update_banner_diary_topic(items)

        data["slides"] = items
        data['visible'] = True
        return data

    @classmethod
    def slide_query(cls, q, position, offset, limit, return_ordering=False, with_offline=False, location=None):
        if location:
            q &= Q(location=location)

        slides = Slide.objects.filter(q)
        if not with_offline:
            now = timezone.now
            slides = slides.filter(position=position, effect_time__lte=now, is_online=True)
            not_end = Q(end_time__isnull=True) | Q(end_time__gte=now)
            slides = slides.filter(not_end).distinct()
        else:
            slides = slides.filter(position=position).order_by('-effect_time')

        # 瀑布流采用ordering作为插入依据
        if return_ordering:
            start_count = offset * limit
            slides = slides.filter(ordering__range=(start_count, start_count + limit))
            slides = slides.order_by('ordering', "-created_time")
        else:
            slides = slides.order_by('ordering', "-created_time")[offset:(offset + limit)]
        return slides

    @classmethod
    def get_visible(cls, position):
        position = str(position)  # 部分前端传入的数据类型是int
        assert position in SLIDE_POSITION
        try:
            visible = gadget_cache.get(cls.RKEY_VISIBLE)
            if not visible:
                return True
            else:
                visible = json.loads(visible)
            if position in visible:
                return visible[position]
            else:
                return True
        except:
            return True

    @classmethod
    def set_visible(cls, position, visible=True):
        position = str(position)  # 部分前端传入的数据类型是int
        assert position in SLIDE_POSITION
        visible_data = gadget_cache.get(cls.RKEY_VISIBLE)
        try:
            visible_data = json.loads(visible_data)
        except:
            visible_data = {}
        visible_data[position] = visible
        gadget_cache.set(cls.RKEY_VISIBLE, json.dumps(visible_data))


class SmallImage(models.Model):
    RKEY_VISIBLE = 'slip_slide_visible'
    MIN_SLIP_SLIDE_CNT = 4  # 少于4个直接invisible
    MAX_SLIP_SLIDE_CNT = 20  # 最多20个

    class Meta:
        verbose_name = u'首页小图'
        verbose_name_plural = u'首页小图'
        app_label = 'api'

    title = models.CharField(verbose_name=u'标题', max_length=128, default='')
    image = ImgUrlField(img_type=IMG_TYPE.SMALLIMAGE, max_length=1024, null=False, blank=False, verbose_name=u'图片地址')
    topic_id = models.IntegerField(verbose_name=u'指定的话题', null=True, blank=True)
    service = models.ForeignKey(Service, verbose_name=u'指定的服务', null=True, blank=True)
    diary_id = models.IntegerField(null=True, blank=True)
    tag = models.ForeignKey(Tag, verbose_name=u'指定的圈子', null=True, blank=True)
    url = models.CharField(max_length=1024, null=True, blank=True, verbose_name=u'跳转的网址')
    ordering = models.IntegerField(default=20, verbose_name=u"展示顺序", help_text=u"小的排在前，大的排在后")
    created_time = models.DateTimeField(auto_now_add=True, verbose_name=u'添加时间')
    effect_time = models.DateTimeField(null=True, verbose_name=u'生效时间')
    end_time = models.DateTimeField(null=True, verbose_name=u'下线时间', blank=True)
    is_online = models.BooleanField(default=True, help_text=u"是否上线", verbose_name=u"上线")
    special = models.ForeignKey(Special, verbose_name=u'指定的福利专题', null=True, blank=True)
    activity_id = models.IntegerField(null=True, blank=True)
    type = models.IntegerField(default=SMALLIMAGE_TYPE.SMALLIMAGE, choices=SMALLIMAGE_TYPE,
                               verbose_name='类型(首页小图/单排横划)')
    new_url = models.CharField(max_length=1024, null=True, blank=True, verbose_name=u'跳转的更美协议')

    def as_dict(self):
        result = to_dict(self, excludes=['ordering', 'created_time', 'effect_time', 'is_online', 'end_time'])
        for key in ["topic", "diary", "activity"]:
            result[key] = result["{}_id".format(key)]
        try:
            if self.special:
                result['special_type'] = self.special.type
        except:
            pass

        return result

    @classmethod
    def get_slip_slides(cls):
        """首页单排横划"""
        res = {
            'visible': cls.get_visible(img_type=SMALLIMAGE_TYPE.SLIPSLIDE),
            'slip_slides': [],
        }
        if not res['visible']:
            return res

        now = timezone.now()
        slip_slides = cls.objects.filter(
            type=SMALLIMAGE_TYPE.SLIPSLIDE,
            is_online=True,
        ).filter(
            Q(end_time__isnull=True) | Q(end_time__gte=now),
            effect_time__lte=now,
        ).order_by('ordering', '-created_time')[:cls.MAX_SLIP_SLIDE_CNT]

        if len(slip_slides) < cls.MIN_SLIP_SLIDE_CNT:
            res['visible'] = False
        else:
            res['slip_slides'] = [slip_slide.as_dict() for slip_slide in slip_slides]

        return res

    @classmethod
    def get_visible(cls, img_type=SMALLIMAGE_TYPE.SLIPSLIDE):
        try:
            visible = gadget_cache.get(cls.RKEY_VISIBLE)
            if not visible:
                return True
            else:
                visible = json.loads(visible)
            if str(img_type) in visible:
                return visible[str(img_type)]
            else:
                return True
        except:
            return True

    @classmethod
    def set_visible(cls, img_type=SMALLIMAGE_TYPE.SLIPSLIDE, visible=True):
        visible_data = gadget_cache.get(cls.RKEY_VISIBLE)
        if not visible_data:
            visible_data = {}
        else:
            visible_data = json.loads(visible_data)
        visible_data[str(img_type)] = visible
        gadget_cache.set(cls.RKEY_VISIBLE, json.dumps(visible_data))


class Gadget(models.Model):
    """首页/社区首页/美购首页 固定模板
    http://jira.gengmei.cc/browse/HERA-11?focusedCommentId=10201&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-10201
    """

    # NOTE: 2016-06-07 boss说放开到100个
    MAX_GADGET_CNT = 100
    MAXTIME = datetime(2039, 1, 1)

    class Meta:
        verbose_name = '固定模板'
        db_table = 'api_gadget'
        app_label = 'api'

    page_type = models.IntegerField(verbose_name='所在页面类型', choices=GADGET_PAGE_TYPE)
    template_type = models.IntegerField(verbose_name='模板类型', choices=GADGET_TEMPLATE_TYPE)
    title = models.CharField(verbose_name='标题', max_length=256, blank=True, default='')
    title_visible = models.BooleanField(verbose_name='是否展示标题', default=True)
    ordering = models.IntegerField(verbose_name='展示顺序(小的在前)', default=0)
    start_time = models.DateTimeField(verbose_name='起始展示时间')
    end_time = models.DateTimeField(verbose_name='终止展示时间', default=MAXTIME)
    created_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    is_online = models.BooleanField(verbose_name='是否展示', default=True)
    image_data = models.TextField(verbose_name='模板数据', default='{}')
    city = models.ManyToManyField(City, verbose_name='展示城市', through='GadgetCity')
    region = models.ManyToManyField(Region, verbose_name='展示城市', through='GadgetRegion')
    is_show = models.BooleanField(verbose_name='是否在新版本展示', default=False)
    user_type = models.CharField('所在页面类型', max_length=2, choices=SLIDE_USER_TYPE, default=SLIDE_USER_TYPE.ALL_USER)
    version = models.CharField(verbose_name=u'版本号', max_length=2, choices=GADGET_VERSION, default=GADGET_VERSION.V1)
    device_type = models.CharField(verbose_name=u'设备类型', max_length=2, choices=SOURCE_POSITION_DEVICE_TYPE.choices,
                                      default=SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE)
    payment_type = models.CharField(u'支付类型', max_length=2, choices=SLIDE_PAYMENT_TYPE.choices,
                                  default=SLIDE_PAYMENT_TYPE.ALL_PAYMENT)
    def get_data(self):
        g = {
            'id': self.id,
            'type': self.template_type,
        }
        if self.title_visible:
            g['title'] = self.title
        g['area'] = {}
        image_data = json.loads(self.image_data)
        if image_data:
            for area, data in image_data.items():
                # area: "a", "b", ...
                g['area'][area] = {
                    'image': data['image'],
                    'url_type': data['url_type'],
                    'url_params': data['url_params'],
                }
                if data['url_type'] == SLIDE_TYPE.SECKILL:
                    g['area'][area]['seckill'] = Special.get_seckill_info()
        return g


    @classmethod
    def get_gadgets(cls, page_type, city_id=None, show_in_v6=False, gadget_ids=None, user_type=None,
                    payment_type=SLIDE_PAYMENT_TYPE.ALL_PAYMENT, platform=SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE):
        res = {
            'gadgets': [],
        }

        now = timezone.now()
        q = Q(page_type=page_type, is_online=True, end_time__gt=now, start_time__lte=now)
        if platform == PLATFORM_CHOICES.IPHONE:
            q &= Q(
                device_type__in=[SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE, SOURCE_POSITION_DEVICE_TYPE.IOS_DEVICE])
        elif platform == PLATFORM_CHOICES.ANDROID:
            q &= Q(
                device_type__in=[SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE, SOURCE_POSITION_DEVICE_TYPE.ANDROID])
        else:
            q &= Q(device_type=SOURCE_POSITION_DEVICE_TYPE.ALL_DEVICE_TYPE)
        q &= Q(payment_type__in=[payment_type, SLIDE_PAYMENT_TYPE.ALL_PAYMENT])
        if show_in_v6:
            q &= Q(is_show=True)

        if gadget_ids:
            q &= Q(id__in=gadget_ids)

        if city_id in WORLD_AREA_TYPE and page_type == GADGET_PAGE_TYPE.INDEX:
            query_region_gadget = None
            query_city_gadget = None
            query_no_city_gadget = q
            gadgets = cls.gadget_city_query(query_region_gadget, query_city_gadget, query_no_city_gadget)
        elif city_id and (page_type == GADGET_PAGE_TYPE.INDEX or page_type == GADGET_PAGE_TYPE.SERVICE_HOME):
            query_region_gadget = None
            region = None
            city = None
            province_id = None
            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_gadget = (
                            q & Q(region=region)
                        )
            except City.DoesNotExist:
                pass

            if province_id:
                # 选北京显示朝阳,选朝阳显示北京
                query = Q(city__province_id=city_id) | Q(city=city_id) | Q(city=province_id)
                query_city_gadget = q & query
            else:
                query_city_gadget = q & (Q(city__province_id=city_id) | Q(city=city_id))

            query_no_city_gadget = q & Q(city__isnull=True, region__isnull=True)

            if region:
                query_city_gadget &= ~Q(region=region)

            gadgets = cls.gadget_city_query(query_region_gadget, query_city_gadget, query_no_city_gadget)
        else:
            gadgets = cls.objects.filter(q).order_by('ordering', '-created_time')[:cls.MAX_GADGET_CNT]

        # 根据用户类型来展示内容 新老用户去不到对应类型的数据则展示全部用户的
        if user_type:
            user_gadgets = []
            all_user_gadgets = []
            for gadget in gadgets:
                if gadget.user_type == user_type:
                    user_gadgets.append(gadget)
                elif gadget.user_type == SLIDE_USER_TYPE.ALL_USER:
                    all_user_gadgets.append(gadget)
            gadgets = user_gadgets if user_gadgets else all_user_gadgets

        for gadget in gadgets:
            g = {
                'id': gadget.id,
                'type': gadget.template_type,
            }
            if gadget.title_visible:
                g['title'] = gadget.title
            g['area'] = {}
            image_data = json.loads(gadget.image_data)
            if image_data:
                for area, data in image_data.items():
                    # area: "a", "b", ...
                    g['area'][area] = {
                        'image': data['image'],
                        'app_new_slide_img': data.get('app_new_slide_img', ''),
                        'url_type': data['url_type'],
                        'url_params': data['url_params'],
                    }
                    if data['url_type'] == SLIDE_TYPE.SECKILL:
                        g['area'][area]['seckill'] = Special.get_seckill_info()
                    elif data['url_type'] == SLIDE_TYPE.NEW_SECKILL:  # 秒杀单场
                        try:
                            sp = Special.objects.get(id=data['url_params']['id'])
                            g['area'][area]['seckill'] = Special.format_seckill_info(sp)
                        except Special.DoesNotExist:
                            g['area'][area]['seckill'] = {}
                    elif data['url_type'] == SLIDE_TYPE.SECKILL_POLYMER:  # 聚合页
                        try:
                            secp = SeckillPolymer.objects.get(id=data['url_params']['id'])
                            _special_id = secp.get_future_special_id()
                            sp = Special.objects.get(id=_special_id)
                            g['area'][area]['seckill'] = Special.format_seckill_info(sp)
                        except Exception:
                            g['area'][area]['seckill'] = {}
            res['gadgets'].append(g)

        return res

    @classmethod
    def gadget_city_query(cls, query_region_gadget, query_city_gadget, query_no_city_gadget,
                          offset=0, limit=10):
        if query_city_gadget:
            city_gadgets = Gadget.objects.filter(query_city_gadget).order_by(
                'ordering', "-created_time")[offset:(offset + limit)]
        else:
            city_gadgets = []

        if query_no_city_gadget:
            no_city_gadgets = Gadget.objects.filter(query_no_city_gadget).order_by(
                'ordering', "-created_time")[offset:(offset + limit)]
        else:
            no_city_gadgets = []

        if query_region_gadget:
            region_gadgets = Gadget.objects.filter(query_region_gadget).order_by(
                'ordering', "-created_time")[offset:(offset + limit)]
        else:
            region_gadgets = []

        order_list = []
        # 优先级：大区＞城市＞空 ordering取的整数 +0.x 排优先级
        for gadget in region_gadgets:
            order_list.append({"ordering": float(gadget.ordering), "val": gadget})

        for gadget in city_gadgets:
            ordering = gadget.ordering + 0.5
            order_list.append({"ordering": float(ordering), "val": gadget})

        for gadget in no_city_gadgets:
            ordering = gadget.ordering + 0.6
            order_list.append({"ordering": float(ordering), "val": gadget})

        order_list = sorted(order_list, key=lambda order_item: order_item['ordering'])
        items = []
        for item in order_list:
            gadget = item['val']
            items.append(gadget)

        return items


class GadgetRegion(models.Model):
    class Meta:
        verbose_name = '固定模版展示大区'
        app_label = 'api'

    gadget = models.ForeignKey(Gadget, verbose_name=u'关联固定模版')
    region = models.ForeignKey(Region, verbose_name=u'关联大区')


class GadgetCity(models.Model):
    class Meta:
        verbose_name = '固定模版展示城市'
        app_label = 'api'

    gadget = models.ForeignKey(Gadget, verbose_name=u'关联固定模版')
    city = models.ForeignKey(City, verbose_name=u'关联城市')


class ButtonGadget(object):
    """http://wiki.gengmei.cc/pages/viewpage.action?pageId=1048720#id-自定义展示位-按钮区.2
    """
    RKEY_PREFIX = 'buttons'
    DEFAULT_LAYOUT = {
        'button_list_visible': True,  # 整体按钮区是否展示
        'button_list': [
            {
                "url": "gengmei://suozhang_column?title=所长说",
                "name": u'所长说',
                "icon": "http://pic.igengmei.com/2015/11/27/2348dfad33-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://diaries?title=看日记",
                "name": u'看日记',
                "icon": "http://pic.igengmei.com/2015/11/27/caeda6c441-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://dig_privacy?title=扒扒扒",
                "name": u'扒扒扒',
                "icon": "http://pic.igengmei.com/2015/11/27/5174373392-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://common_webview?url=http://backend.test.gengmei.cc/hybrid/activity/list",
                "name": u'免费送',
                "icon": "http://pic.igengmei.com/2015/11/27/3b748d852d-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://star_users?title=达人榜",
                "name": u'达人榜',
                "icon": "http://pic.igengmei.com/2015/11/27/10b5467c26-thumb",
                "visible": True,
            },
            {
                "url": "",
                "name": u'',
                "icon": "",
                "visible": False,
            },
            {
                "url": "",
                "name": u'',
                "icon": "",
                "visible": False,
            },
            {
                "url": "",
                "name": u'',
                "icon": "",
                "visible": False,
            },
        ],
    }

    @classmethod
    def _gen_key(cls, page_type):
        return ':'.join((cls.RKEY_PREFIX, str(page_type)))

    @classmethod
    def set_buttons(cls, page_type, button_list, button_list_visible=True):
        buttons = []
        for _ in button_list:
            assert isinstance(_, dict)
            buttons.append({
                'name': _.get('name'),
                'icon': _.get('icon'),
                'url': _.get('url'),
                'visible': _.get('visible', True)
            })
        res = {
            'button_list_visible': button_list_visible,
            'button_list': buttons,
        }
        rkey = cls._gen_key(page_type)
        gadget_cache.set(rkey, json.dumps(res))

    @classmethod
    def get_buttons(cls, page_type, mask_invisible=False):
        assert page_type in GADGET_PAGE_TYPE
        rkey = cls._gen_key(page_type)
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_LAYOUT
            else:
                res = json.loads(res)
            if mask_invisible:
                res['button_list'] = filter(lambda _: _.get('visible', True), res['button_list'])
            return res
        except:
            return cls.DEFAULT_LAYOUT


class ButtonSideslip(object):
    """
        按钮横滑
    """
    RKEY_PREFIX = 'buttons'
    DEFAULT_SIDESLIP = {
        'button_list': [
            {
                "url": "gengmei://suozhang_column?title=所长说",
                "name": u'所长说',
                "rank": '1',
                "icon": "http://pic.igengmei.com/2015/11/27/2348dfad33-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://diaries?title=看日记123123123",
                "name": u'看日记',
                "rank": '2',
                "icon": "http://pic.igengmei.com/2015/11/27/caeda6c441-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://dig_privacy?title=扒扒扒",
                "name": u'扒扒扒',
                "rank": '3',
                "icon": "http://pic.igengmei.com/2015/11/27/5174373392-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://common_webview?url=http://backend.test.gengmei.cc/hybrid/activity/list",
                "name": u'免费送',
                "rank": '4',
                "icon": "http://pic.igengmei.com/2015/11/27/3b748d852d-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://star_users?title=达人榜",
                "name": u'达人榜',
                "rank": '5',
                "icon": "http://pic.igengmei.com/2015/11/27/10b5467c26-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://star_users?title=达人榜",
                "name": u'达人榜',
                "rank": '6',
                "icon": "http://pic.igengmei.com/2015/11/27/10b5467c26-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://star_users?title=达人榜",
                "name": u'达人榜',
                "rank": '7',
                "icon": "http://pic.igengmei.com/2015/11/27/10b5467c26-thumb",
                "visible": True,
            },
            {
                "url": "gengmei://star_users?title=达人榜",
                "name": u'达人榜',
                "rank": '8',
                "icon": "http://pic.igengmei.com/2015/11/27/10b5467c26-thumb",
                "visible": True,
            },
        ],
    }

    @classmethod
    def _gen_key(cls, page_type):
        return ':'.join((cls.RKEY_PREFIX, str(page_type)))

    @classmethod
    def set_buttons(cls, page_type, button_list):
        buttons = []
        for _ in button_list:
            assert isinstance(_, dict)
            buttons.append({
                'name': _.get('name'),
                'icon': _.get('icon'),
                'url': _.get('url'),
                'rank': _.get('rank'),
                'visible': _.get('visible', True)
            })
        res = {
            'button_list': buttons,
        }
        rkey = cls._gen_key(page_type)
        gadget_cache.set(rkey, json.dumps(res))

    @classmethod
    def get_buttons(cls, page_type, mask_invisible=False):
        rkey = cls._gen_key(page_type)
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_SIDESLIP
            else:
                res = json.loads(res)
            if mask_invisible:
                res['button_list'] = filter(lambda _: _.get('visible', True), res['button_list'])
            return res
        except:
            return cls.DEFAULT_SIDESLIP


class ZoneLayout(object):
    """热门圈子layout
    """
    RKEY_PREFIX = 'zones'

    DEFAULT_LAYOUT = {
        'zone_visible': True,
        'hot_in_24hours': {
            'visible': True,  # 是否显示24小时最热
            'icon': 'http://pic.igengmei.com/2015/09/18/49a291d255-thumb',
        }
    }

    @classmethod
    def _gen_key(cls):
        return cls.RKEY_PREFIX

    @classmethod
    def set_zone_layout(cls, zone_visible, hot_in_24hours):
        rkey = cls._gen_key()
        res = {
            'zone_visible': zone_visible,
            'hot_in_24hours': hot_in_24hours,
        }
        gadget_cache.set(rkey, json.dumps(res))

    @classmethod
    def get_zone_layout(cls):
        rkey = cls._gen_key()
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_LAYOUT
            else:
                res = json.loads(res)
            return res
        except:
            return cls.DEFAULT_LAYOUT


class CommunityDeploy(object):
    """
    社区首页配置
    """

    RKEY_PREFIX = 'communitydeploy'

    DEFAULT_DEPLOY = {
        'activity': True,
        'zone': True,
        'community': False,
    }

    @classmethod
    def get_community_deploy(cls):
        rkey = cls.RKEY_PREFIX
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_DEPLOY
            else:
                res = json.loads(res)
            return res
        except:
            return cls.DEFAULT_DEPLOY

    @classmethod
    def set_community_deploy(cls, deploy_info):
        rkey = cls.RKEY_PREFIX
        res = deploy_info
        gadget_cache.set(rkey, json.dumps(res))


class TabConfigDeploy(object):
    """
    底部栏色值、icon配置
    """
    RKEY_PREFIX = 'tabconfigdeploy'

    DEFAULT_DEPLOY = [
        {
            'icon_normal': "",
            'icon_pressed': "",
            'colour_normal': "",
            'colour_pressed': ""
        },
        {
            'icon_normal': "",
            'icon_pressed': "",
            'colour_normal': "",
            'colour_pressed': ""
        },
        {
            'icon_normal': "",
            'icon_pressed': "",
            'colour_normal': "",
            'colour_pressed': ""
        },
        {
            'icon_normal': "",
            'icon_pressed': "",
            'colour_normal': "",
            'colour_pressed': ""
        },
        {
            'icon_normal': "",
            'icon_pressed': "",
            'colour_normal': "",
            'colour_pressed': ""
        },
        {
            'icon_normal': "",
            'icon_pressed': "",
            'colour_normal': "",
            'colour_pressed': ""
        },
    ]

    @classmethod
    def _gen_key(cls):
        return cls.RKEY_PREFIX

    @classmethod
    def get_deploy(cls, rkey='tabconfigdeploy'):
        # rkey = cls._gen_key()
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_DEPLOY
            else:
                res = json.loads(res)
                if len(res) == 5:
                    res.insert(3, {
                        'icon_normal': "",
                        'icon_pressed': "",
                        'colour_normal': "",
                        'colour_pressed': ""
                    })
            return res
        except:
            return cls.DEFAULT_DEPLOY

    @classmethod
    def set_deploy(cls, deploy_info, rkey='tabconfigdeploy'):
        # rkey = cls._gen_key()
        res = deploy_info
        gadget_cache.set(rkey, json.dumps(res))


class IndextabConfig(object):
    """
    首页顶部横滑tab配置
    config：[{tab_title:u'测试tab', is_online: True, ordering:1/None, special_id: 123}]
    """
    key = 'indextab_config'
    default_config = [

    ]

    @classmethod
    def get(cls):
        try:
            config = json.loads(index_tab_cache.get(cls.key))
        except:
            config = cls.default_config
        return config

    @classmethod
    def set(cls, tab_config):
        if not tab_config:
            return

        try:
            index_tab_cache.set(cls.key, json.dumps(tab_config))
        except:
            index_tab_cache.error(u'设置首页顶部横滑tab配置失败')


class CategoryGadget(RequestSourceModel):
    class Meta:
        verbose_name = '品类模块'
        db_table = 'api_categorygadget'
        app_label = 'api'

    title = models.CharField(verbose_name=u'标题', max_length=128)
    is_online = models.BooleanField(default=True, verbose_name=u"是否上线")
    start_time = models.DateTimeField(verbose_name=u'开始时间')
    end_time = models.DateTimeField(verbose_name='结束时间', blank=True, null=True)
    image_data = models.TextField(verbose_name='模板数据')


class HomepageOperate(models.Model):
    class Meta:
        verbose_name = '首页运营位统一'
        db_table = 'api_homepageoperate'
        app_label = 'api'

    service_type = models.CharField(u'业务类型', max_length=2, choices=SLIDE_SERVICE_TYPE, default=SLIDE_SERVICE_TYPE.DEAL)
    jump_type = models.CharField(u'类型', max_length=2, choices=HOMEPAGE_OPERATE_TYPE, default=HOMEPAGE_OPERATE_TYPE.GIFT)
    location = models.CharField(u'位置', max_length=2, choices=HOMEPAGE_OPERATE_LOCATION,
                                default=HOMEPAGE_OPERATE_LOCATION.OPERATE_A)

    title = models.CharField(u'标题', max_length=128)
    image = ImgUrlField(u'图片', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    rank = models.IntegerField(u'展示顺序', default=999999)

    user_type = models.CharField(u'用户类型', max_length=2, choices=SLIDE_USER_TYPE, default=SLIDE_USER_TYPE.ALL_USER)
    payment_type = models.CharField(u'支付类型', max_length=2, choices=SLIDE_PAYMENT_TYPE,
                                    default=SLIDE_PAYMENT_TYPE.ALL_PAYMENT)
    is_online = models.BooleanField(u'是否上线', default=False)

    jump = models.CharField(u'各类型ID、URL等信息', max_length=1024, null=True, blank=True)
    start_time = models.DateTimeField(u'开始时间', blank=True)
    end_time = models.DateTimeField(u'结束时间', blank=True)

    regions = models.ManyToManyField(Region, verbose_name=u'展示大区')
    cities = models.ManyToManyField(City, verbose_name=u'展示城市')

    last_time = models.DateTimeField(u'最后操作时间', null=True, blank=True, auto_now=True)
    last_operator = models.ForeignKey(User, verbose_name=u'最后操作人')

    def banner_data(self):
        countdown = 0
        is_new_special = False
        seckill_id = self.get_valid_seckill_pk()
        if seckill_id:
            countdown = (Special.objects.get(id=seckill_id).end_time - timezone.now()).total_seconds()

        if str(HOMEPAGE_OPERATE_TYPE.SPECIAL) == str(self.jump_type):
            try:
                is_new_special = Special.objects.get(id=self.jump).is_new_special
            except:
                pass

        result = {
            'id': self.id,
            'rank': self.rank,
            'image': self.image,
            'title': self.title,
            'jump_type': self.jump_type,
            'jump': self.jump,
            'location': self.location,
            'is_new_special': is_new_special,
            'is_seckill': self.jump_type == HOMEPAGE_OPERATE_TYPE.SECKILL,
            'countdown': countdown,
            'entity_id': self.jump if self.jump_type != HOMEPAGE_OPERATE_TYPE.SECKILL else seckill_id,
            'service_type': self.service_type
        }

        return result

    def get_valid_seckill_pk(self):
        if self.jump_type != HOMEPAGE_OPERATE_TYPE.SECKILL:
            return None

        try:
            seckill_id = int(self.jump)
        except (ValueError, TypeError):
            seckill_ids = [int(s) for s in self.jump.split("/") if s.isdigit()]
            if len(seckill_ids) != 1:
                return None
            seckill_id = seckill_ids[0]

        now = timezone.now()
        if Special.objects.filter(id=seckill_id, is_online=True, start_time__lte=now, end_time__gte=now).exists():
            return seckill_id

    def __str__(self):
        return "{}:{}".format(self.jump_type, self.jump)


class TabOperate(models.Model):
    class Meta:
        verbose_name = '首页tab运营池'
        db_table = 'api_tab_operate'
        app_label = 'api'

    tab = models.CharField(u'首页Tab', choices=TAB_TYPES_NEW, default=TAB_TYPES_NEW.CHOICE, max_length=30)
    card_type = models.CharField(u'内容类型',choices=CARD_TYPE, default=CARD_TYPE.DIARY, max_length=30)
    card_id =models.IntegerField(u'内容id')
    rank = models.IntegerField(u'排序', default=1)
    is_online = models.BooleanField(u'是否上线', default=True)

    @property
    def data(self):
        return {
            'card_type': self.card_type,
            'card_id': self.card_id,
        }


class HomepageIcon(models.Model):
    class Mate:
        verbose_name = '首页icon'
        app_label = 'api'

    name = models.CharField(u'活动名称', max_length=16)
    image = ImgUrlField(u'icon图标', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image_new = ImgUrlField(u'icon图标（新）', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True)

    jump_type = models.CharField(u'类型', max_length=2, choices=HOMEPAGE_OPERATE_TYPE, default=HOMEPAGE_OPERATE_TYPE.ALL_CATEGORY)
    jump = models.CharField(u'跳转到各类型ID、URL等信息', max_length=1024, null=True, blank=True)
    service_type = models.CharField(u'业务类型', max_length=2, choices=SLIDE_SERVICE_TYPE, default=SLIDE_SERVICE_TYPE.DEAL)

    rank = models.IntegerField(u'展示顺序', default=999999)

    user_type = models.CharField(u'用户类型', max_length=2, choices=SLIDE_USER_TYPE, default=SLIDE_USER_TYPE.ALL_USER)
    payment_type = models.CharField(u'支付类型', max_length=2, choices=SLIDE_PAYMENT_TYPE,
                                    default=SLIDE_PAYMENT_TYPE.ALL_PAYMENT)

    is_online = models.BooleanField(u'是否上线', default=False)

    start_time = models.DateTimeField(u'开始时间', blank=True)
    end_time = models.DateTimeField(u'结束时间', blank=True)

    regions = models.ManyToManyField(Region, verbose_name=u'展示大区')
    cities = models.ManyToManyField(City, verbose_name=u'展示城市')

    last_time = models.DateTimeField(u'最后操作时间', null=True, blank=True, auto_now=True)
    last_operator = models.ForeignKey(User, verbose_name=u'最后操作人')

    version = models.CharField(verbose_name=u'版本号', max_length=2, choices=HOME_PAGE_ICON_VERSION, default=HOME_PAGE_ICON_VERSION.V1)

    def icon_data(self, new_img=False):
        result = {
            'id': self.id,
            'rank': self.rank,
            'image': self.image_new if (new_img and self.image_new) else self.image,
            'name': self.name,
            'jump_type': self.jump_type,
            'jump': self.jump,
        }
        return result


class FestivalHomepageIcon(models.Model):
    class Meta:
        verbose_name = '节日首页icon'
        db_table = 'api_festival_homepage_icon'
        app_label = 'api'

    name = models.CharField(u'标题', max_length=32)
    font_color = models.CharField(u'字体颜色', max_length=2, choices=FONT_COLOR, default=FONT_COLOR.BLACK)

    background_image = ImgUrlField(u'背景图片', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image1 = ImgUrlField(u'图片1', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image2 = ImgUrlField(u'图片2', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image3 = ImgUrlField(u'图片3', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image4 = ImgUrlField(u'图片4', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image5 = ImgUrlField(u'图片5', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image6 = ImgUrlField(u'图片6', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image7 = ImgUrlField(u'图片7', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image8 = ImgUrlField(u'图片8', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image9 = ImgUrlField(u'图片9', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    image10 = ImgUrlField(u'图片10', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )
    start_time = models.DateTimeField(u'开始时间', blank=True)
    end_time = models.DateTimeField(u'结束时间', blank=True)
    regions = models.ManyToManyField(Region, verbose_name=u'展示大区')
    cities = models.ManyToManyField(City, verbose_name=u'展示城市')
    last_time = models.DateTimeField(u'最后操作时间', null=True, blank=True, auto_now=True)
    last_operator = models.ForeignKey(User, verbose_name=u'最后操作人')
    user_type = models.CharField(u'用户类型', max_length=2, choices=SLIDE_USER_TYPE, default=SLIDE_USER_TYPE.ALL_USER)
    payment_type = models.CharField(u'支付类型', max_length=2, choices=SLIDE_PAYMENT_TYPE,
                                    default=SLIDE_PAYMENT_TYPE.ALL_PAYMENT)
    is_online = models.BooleanField(u'是否上线', default=True)
    update_time = models.DateTimeField(auto_now=True, verbose_name=u"最近修改时间")
    create_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True)
    version = models.CharField(verbose_name=u'版本号', max_length=2, choices=FESTIVAL_HOMEPAGE_ICON_VERSION, default=FESTIVAL_HOMEPAGE_ICON_VERSION.V1)
    min_version = models.CharField(u'最低版本限制', max_length=30, default='')
    max_version = models.CharField(u'最高版本限制', max_length=30, default='')

    def img_data(self):
        # 还需要返回user_type  payment_type ，么。 查询的sql已经过滤了。根据这个人的id进行了过滤
        result = {}
        result['font_color']=self.font_color
        result['background_img'] = self.background_image
        result['festival_img'] = [self.image1, self.image2, self.image3, self.image4, self.image5, self.image6,
                                  self.image7, self.image8, self.image9, self.image10]
        return result


class HomepageActivity(models.Model):
    class Mate:
        verbose_name = '首页活动入口'
        app_label = 'api'

    name = models.CharField(u'活动名称', max_length=16)
    image = ImgUrlField(u'icon图标', img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=True, blank=True, )

    jump_type = models.CharField(u'类型', max_length=2, choices=HOMEPAGE_OPERATE_TYPE, default=HOMEPAGE_OPERATE_TYPE.GIFT)
    jump = models.CharField(u'跳转到各类型ID、URL等信息', max_length=1024, null=True, blank=True)
    service_type = models.CharField(u'业务类型', max_length=2, choices=SLIDE_SERVICE_TYPE, default=SLIDE_SERVICE_TYPE.DEAL)

    location = models.CharField(u'位置', max_length=2, choices=HOMEPAGE_OPERATE_LOCATION,
                                default=HOMEPAGE_OPERATE_LOCATION.OPERATE_A)

    user_type = models.CharField(u'用户类型', max_length=2, choices=SLIDE_USER_TYPE, default=SLIDE_USER_TYPE.ALL_USER)
    payment_type = models.CharField(u'支付类型', max_length=2, choices=SLIDE_PAYMENT_TYPE,
                                    default=SLIDE_PAYMENT_TYPE.ALL_PAYMENT)

    is_online = models.BooleanField(u'是否上线', default=False)

    start_time = models.DateTimeField(u'开始时间', blank=True)
    end_time = models.DateTimeField(u'结束时间', blank=True)

    regions = models.ManyToManyField(Region, verbose_name=u'展示大区')
    cities = models.ManyToManyField(City, verbose_name=u'展示城市')

    last_time = models.DateTimeField(u'最后操作时间', null=True, blank=True, auto_now=True)
    last_operator = models.ForeignKey(User, verbose_name=u'最后操作人')

    def data(self):
        result = {
            "icon_image": self.image,
            "jump_type": self.jump_type,
            "jump": self.jump,
            "id": self.id,
        }
        return result


class TabOperateV2(models.Model):
    class Meta:
        verbose_name = '首页tab运营池'
        db_table = 'api_tab_operate_v2'
        app_label = 'api'

    name = models.CharField(u'名称', max_length=16)
    tags = models.ManyToManyField(Tag, verbose_name=u'关联tag')
    rank = models.IntegerField(u'排序', default=1)
    tab_classify = models.CharField(u'TAB类型', max_length=16, choices=TAB_INDEX_CLASSIFY,
                                    default=TAB_INDEX_CLASSIFY.NORMAL)
    is_online = models.BooleanField(u'是否上线', default=True)

    version = models.CharField(verbose_name=u'版本号', max_length=2, choices=TAB_OPERATE_VERSION, default=TAB_OPERATE_VERSION.V1)


class TabOperateV2TagV3(models.Model):
    class Meta:
        verbose_name = '首页tab运营池关联标签'
        db_table = 'api_tab_operate_v2_tag_v3'
        app_label = 'api'

    tab_operate_v2_id = models.IntegerField(verbose_name=u'首页tab运营池', db_index=True)
    tag_v3_id = models.IntegerField(verbose_name=u'新标签', db_index=True)
    create_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True)
    update_time = models.DateTimeField(verbose_name=u'更新时间', auto_now=True)


class FeedOperateV2(models.Model):
    class Mate:
        verbose_name = 'feeds流插入'
        app_label = 'api'
    name = models.CharField(verbose_name= u'名称', max_length=32, null=False)
    location = models.CharField(u'位置', max_length=32, choices=TAB_TYPES_NEW, default=TAB_TYPES_NEW.TAB_OPERATE)
    tab_id = models.IntegerField(verbose_name= u'新横滑tab_id', default=0)
    image = ImgUrlField(img_type=IMG_TYPE.NOWATERMARK, max_length=1024, null=False, blank=False, verbose_name=u'图片地址')
    service_type = models.CharField(verbose_name= u'业务类型', max_length=2, choices=FEED_SERVICE_TYPE, default=FEED_SERVICE_TYPE.SUPPLY)
    show_type = models.IntegerField(verbose_name= u'展示位置', choices=FEED_SHOW_TYPE, default=FEED_SHOW_TYPE.D)
    card_type = models.CharField(verbose_name='feed卡片类型', choices=INDEX_CARD_TYPE, default=INDEX_CARD_TYPE.DIARY, max_length=8)
    card_id = models.CharField(verbose_name=u'跳转到卡片的ID', max_length=32)
    regions = models.ManyToManyField(Region, verbose_name=u'展示大区')
    cities = models.ManyToManyField(City, verbose_name=u'展示城市')
    user_type = models.CharField(u'用户类型', max_length=2, choices=SLIDE_USER_TYPE, default=SLIDE_USER_TYPE.ALL_USER)
    payment_type = models.CharField(verbose_name= u'支付类型', max_length=2, choices=SLIDE_PAYMENT_TYPE,
                                    default=SLIDE_PAYMENT_TYPE.ALL_PAYMENT)
    is_online = models.BooleanField(verbose_name= u'是否上线', default=False)
    rank = models.IntegerField(verbose_name= u'展示顺序', default=999999)
    width = models.IntegerField(verbose_name="图片宽度", default=0)
    height = models.IntegerField(verbose_name="图片高度", default=0)
    start_time = models.DateTimeField(u'开始时间', blank=True)
    end_time = models.DateTimeField(u'结束时间', blank=True)
    update_time = models.DateTimeField(auto_now=True, verbose_name=u"最近修改时间")
    create_time = models.DateTimeField(verbose_name=u'创建时间', auto_now_add=True)

    version = models.CharField(verbose_name=u'版本号', max_length=2, choices=FEED_OPERATE_VERSION, default=FEED_OPERATE_VERSION.V1)
    relevance_tag = models.IntegerField(verbose_name= u'关联的需求标签id', default=0)
    plastic_template = models.CharField(verbose_name= u'关联的整形模板', max_length=64, default="")
    tab_type = models.IntegerField(verbose_name=u'展示位置', choices=FEED_TAB_TYPE)

    version_limit = models.CharField(verbose_name=u'最低版本限制', max_length=32, default="")


class BannerFreeRecruitment(object):
    """
        免费招募列表页顶部banner配置
    """
    RKEY_PREFIX = 'freerecruitment'
    DEFAULT_SIDESLIP = {
        'banner_list': [
            {
                "url": "",
                "icon": "",
            },
            {
                "url": "",
                "icon": "",
            },
            {
                "url": "",
                "icon": "",
            },
            {
                "url": "",
                "icon": "",
            },
            {
                "url": "",
                "icon": "",
            },
            {
                "url": "",
                "icon": "",
            },
        ],
        "is_synchronize_app": False,
    }

    @classmethod
    def _gen_key(cls, page_type):
        return ':'.join((cls.RKEY_PREFIX, str(page_type)))

    @classmethod
    def set_banners(cls, page_type, banner_info):
        banners = []
        for _ in banner_info['banner_list']:
            assert isinstance(_, dict)
            banners.append({
                'icon': _.get('icon'),
                'url': _.get('url'),
            })
        res = {
            'banner_list': banners,
            'is_synchronize_app': banner_info['is_synchronize_app']
        }
        rkey = cls._gen_key(page_type)
        gadget_cache.set(rkey, json.dumps(res))

    @classmethod
    def get_banners(cls, page_type):
        rkey = cls._gen_key(page_type)
        try:
            res = gadget_cache.get(rkey)
            if not res:
                res = cls.DEFAULT_SIDESLIP
            else:
                res = json.loads(res)
            return res
        except:
            return cls.DEFAULT_SIDESLIP
