# -*- coding: utf-8 -*-
from __future__ import absolute_import
import datetime
import json
import time
import random
import urlparse

from django.db.models import Q
from django.db import transaction
from django.conf import settings
from gm_types.gaia import (
    POINTS_TYPE,
    POINTS_OPERATION,
    SIGN_TYPE_V2,
    SIGN_CALENDAR_TYPE_V2,
    VIRTUAL_PRIZE_TYPE_V2,
    SERVICE_DISPLAY_PORT,
    SIGN_TASK_TYPE,
    SIGN_GIFT_STATUS,
    PRIZE_STATUS,
    )
from gm_types.error import ERROR as CODES
from gm_types.apollo.error import ERROR
from gm_types.point.enum import SIGN_ACTIVITY_EXCHANGE_GOODS_TYPE, GOODS_CLAIM_STATUS

from api.models import Special, SpecialRegion
from rpc.tool.protocol import gm_protocol

from api.manager.service_info_manager import get_toc_spu_info_list_mapping_by_spu_ids
from api.tool.geo_tool import get_location_tag_id_by_city_id
from rpc.context import get_rpc_remote_invoker
from rpc.decorators import (
    bind,
    bind_context,
)
from api.models.sign_v2 import (
    SignBigPrizeV2, SignConfigV2, SignRecordLogV2, SignUserExchangedPrize,
    SignUserInfoV2, ExchangedRecordV2, SignBlindBox, SignUserBlindBox, SignBlindExchangePrize,
    SignTaskUserFinish, SignAssistUser, SignPrizeV3, ExchangedRecordV3
)
from api.models.coupon import CouponGift
from point.models import PointsInfo, Points
from api.models.doctor import Doctor
from api.tasks.sign_push_ontime import sign_rush_prize, sign_pay_finish_task
from api.tool.coupon_tool import user_get_gift_by_displayab_page
from api.tool.user_tool import get_user_from_context, get_user_by_id
from rpc.tool.log_tool import logging_exception
from rpc.tool.error_code import gen
from rpc.exceptions import GaiaRPCFaultException
from rpc.cache import sign_rush_cache, sign_task_cache
from rpc.tool.log_tool import info_logger
from search.utils.area import get_region_by_city_id

LuckDrawCost = 50
RushBuyHour = 16
SIGN_POINTS = 5
rush_cache_key = "sign_rush_user_list"
browse_service_cache_key = 'browse_service_cache:{user_id}'
rush_cache_expire_time = 3600 * 10
task_limit_everyday = {
    '1': (10, 20),          # 逛商品
    '2': (10, 200),         # 下单 每天10次 每次200
    '3': (5, 50),           # 好友助力
    '4': (1, 50),           # 扫脸
    '5': (1, 50),           # 测肤
    '6': (1, 50),           # 下载
    '7': (3, 20),           # 老版本好友助力
    '9': (10, 20),          # 逛专题 任务
}
task_to_mark = {
    "1": "browse",
    "2": "pay_order",
    "3": "friend_assist",
    "4": "scan_face",
    "5": "sacn_skin",
    "6": "download",
    "7": "old_assist",
    "9": "browse_special",
}

alert_message = {
    '1': '浏览商品任务已完成！',  # 逛商品
    '2': '商品下单任务已完成！',  # 下单 每天10次 每次200
    '3': '好友助力任务已完成！',  # 好友助力
    '4': '其他任务任务已完成！',  # 扫脸
    '9': '浏览会场任务已完成！',      # 逛专题 加积分
}
start_prize_time = datetime.date(year=2019, month=10, day=25)


record_user_special = "record_special_{user_id}"
affect_days = 7
XCX_URL_WITH_TASK = u"/packageTrade/pages/welfare/detail/detail?welfare_id={service_id}&type=common&" \
                    u"sign_task_time={stay_seconds}"
XCX_URL_WITHOUT_TASK = u"/packageTrade/pages/welfare/detail/detail?welfare_id={service_id}&type=common"


class Test(object):
    pass


def get_coupon_data(coupon_gift_id):
    """获取优惠券的价值"""
    gift = CouponGift.objects.filter(id=coupon_gift_id).first()

    return gift.value if gift and gift.value else 0


def handle_sign_date(online_time, sign_dates):
    """
    获取日期数组中大于等于online_time的最长连续时间段长度
    :param online_time:
    :param sign_dates:  日期数组
    :return:
    """
    t_length, _length, _date, temp_date = 0, 0, None, None
    for t_date in sign_dates:
        if t_date < online_time:
            continue

        if not _date:
            _date, _length = t_date, 1
            if t_date + datetime.timedelta(days=-1) == temp_date:
                _length += 1
            continue

        if t_date + datetime.timedelta(days=-1) == _date:
            _date, _length = t_date, _length + 1
        else:
            t_length = _length if _length > t_length else t_length
            _date, temp_date = None, t_date

    return max(_length, t_length)


def handle_sign_length(sign_dates):
    """
    处理初始连续日期段的长度
    :param sign_dates: 日期数组
    :return:
    """
    t_length, _date = 0, None

    today = datetime.datetime.now().date()
    yesterday = today - datetime.timedelta(days=1)
    if len(sign_dates)==0 or sign_dates[0] not in [today, yesterday]:
        return t_length

    for t_date in sign_dates:
        if not _date:
            _date, t_length = t_date, 1
            continue

        if t_date + datetime.timedelta(days=1) == _date:
            _date, t_length = t_date, t_length + 1
        else:
            break
    return t_length


def create_share_code(user_id=None):
    if not user_id:
        return ''

    share_code = '{month}{user_id}'.format(month=datetime.datetime.now().month, user_id=user_id)
    return share_code


def  judge_prize_exchanged(have_blind_ids, prize_blind_ids):
    for blind_card_id in prize_blind_ids:
        if blind_card_id not in have_blind_ids:
            return False

    return True


def get_service_browse_task_status(user_id, service_ids):
    result = {}
    if not user_id:
        return result

    cache_key = browse_service_cache_key.format(user_id=user_id)
    cached_service_ids = sign_task_cache.smembers(cache_key)
    cached_service_len = sign_task_cache.scard(cache_key)
    for _id in service_ids:
        result[str(_id)] = False if cached_service_len >= 10 else str(_id) not in cached_service_ids

    return result


def get_special(read_special_ids=[], add_sign_chance=True):
    """小程序补签不跳转专题
        1--美购专题  2--秒杀专场  3--秒杀聚合
        4--新专题
    """
    sign_config = SignConfigV2.objects.first()
    special_list = json.loads(sign_config.operate_config)
    specials = []
    channel = u"signcalendar_15" if add_sign_chance else u"signcalendar_0"
    for special_item in special_list:
        if not special_item.get("gm_url"):
            continue

        gm_url = ""
        if special_item.get("special_type") == "4":
            is_new_special = 1 if special_item.get("new_special") else 0
            gm_url = gm_protocol.get_service_special_list(id=special_item.get("gm_url"),
                                                          is_new_special=is_new_special,
                                                          channel=channel)

            gm_url = gm_url.replace("&is_new_special=0", "")

        # if special_item.get("special_type") == "2":
        #     _url = urlparse.urljoin(settings.BACKEND_API_HOST, 'phantom/seckill/{_id}'.format(_id=special_item['gm_url']))
        #     gm_url = gm_protocol.get_webview(_url)
        # if special_item.get("special_type") == "3":
        #     # 秒杀聚合
        #     _url = urlparse.urljoin(settings.BACKEND_API_HOST,
        #                             'phantom/seckill_polymer/{_id}'.format(_id=special_item['gm_url']))
        #     gm_url = gm_protocol.get_webview(_url)
        else:
            continue

        specials.append({
            "id": int(special_item.get("gm_url")),
            "gm_url": gm_url,
            "special_type": special_item.get("special_type") or 0,
        })

    new_special_list = []
    for special in specials:
        if str(special.get("id")) not in read_special_ids:
            new_special_list.append(special)

    if not new_special_list:
        return specials

    return new_special_list


@bind("api/user/to_sign")
def to_sign(user_id=None):
    """签到接口"""
    # user = get_user_from_context(ctx)
    if not user_id:
        return gen(CODES.MESSAGE_UNKNOWN_USER)
    user = get_user_by_id(user_id)

    if user_id and Doctor.objects.filter(user_id=user_id):
        return gen(CODES.IS_DOCTOR)  #机构号

    config = SignConfigV2.objects.first()

    cycle = config.cycle if config else SIGN_POINTS

    #日志表添加log记录
    sign_log = SignRecordLogV2.objects.filter(user_id=user_id).order_by("-sign_time").first()  #上次签到记录
    sign_user, status = SignUserInfoV2.objects.get_or_create(user_id=user_id)

    try:
        # 添加签到记录
        today_log = SignRecordLogV2.objects.create(user_id=user_id, sign_time=datetime.date.today(), sign_type=SIGN_TYPE_V2.NOMALR_SIGN)
        prize_point_list = [50, 75, 100, 100, 100, 125, 125, 125, 200, 0]
        day_turn = sign_user.last_days % 10
        coin = prize_point_list[day_turn]
        if coin:
            with transaction.atomic():
                p = Points(
                    user=user,
                    operation=POINTS_OPERATION.ADD,
                    reason=POINTS_TYPE.SIGN_IN,
                    number=coin,
                )
                p.save()
                user.person.points += coin
                user.person.save()
    except Exception:
        # logging_exception()
        return gen(CODES.HAS_SIGN)

    if status:
        sign_user.newest_time = datetime.date.today()
        sign_user.last_days = 1
        # sign_user.points_count = cycle            # 移除签到积分奖励，改为美分奖励
        sign_user.save()
    else:
        sign_user.newest_time = datetime.date.today()
        if sign_log and (sign_log.sign_time + datetime.timedelta(days=1)) >= datetime.date.today():
            sign_user.last_days += 1
        else:
            sign_user.last_days = 1
        # sign_user.points_count += (sign_user.last_days * cycle) if sign_user.last_days * cycle < 35 else 35

        sign_user.save()

    return {"status": 1}


@bind("api/user/sign_base_data")
def get_sign_data(user_id=None):
    """获取签到页面基础数据（计划有两个gaia接口， 1个是用户已登录、一个是用户未登录）"""
    result = {
        "cycle_prizes": [],
        "jump_config": [],
        "cycle_days": 0,
        "rule": "",
        "space_days": 0,
        "has_sign_days": 0,
        "last_days": 0,
        "add_sign_number": 0,
        "show_tip": True,
        "is_remind": False,
        "share_code": "",
        "sign_status": 0,
    }
    sign_config = SignConfigV2.objects.first()

    if not sign_config:
        return result

    prize_list = json.loads(sign_config.prize)
    for prize in prize_list:
        prize['last_days'] = int(prize['last_days']) if prize.get('last_days') else 0
        prize['prize_type'] = int(prize['prize_type']) if prize.get('prize_type') else 0
        prize['prize_value'] = int(prize['prize_value']) if prize.get('prize_value') else 0
        if prize.get("prize_type") == VIRTUAL_PRIZE_TYPE_V2.COUPON_TYPE:
            prize['prize_value'] = get_coupon_data(coupon_gift_id=prize.get("prize_value"))

    result.update({
        "cycle_prizes": prize_list,
        "jump_config": json.loads(sign_config.operate_config),
        "cycle_days": sign_config.cycle,
        "rule": sign_config.rule,
    })

    if user_id:
        user_id = int(user_id)
        sign_user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
        if not sign_user_info:
            SignUserInfoV2.objects.create(user_id=user_id, share_code=create_share_code(user_id=user_id))
            return result

        if sign_user_info.newest_time and datetime.date.today() == sign_user_info.newest_time:
            result['sign_status'] = SIGN_TYPE_V2.NOMALR_SIGN            #用户已签到
        elif sign_user_info.newest_time and datetime.date.today() == (sign_user_info.newest_time + datetime.timedelta(days=1)):
            result['sign_status'] = SIGN_CALENDAR_TYPE_V2.CAN_NOT_SIGN      #当天还未签到
        elif not sign_user_info.newest_time:
            result['sign_status'] = SIGN_CALENDAR_TYPE_V2.CAN_NOT_SIGN      #第一次签到，还未签到
        else:
            result['sign_status'] = SIGN_CALENDAR_TYPE_V2.NO_SIGN    #断签了

        result['has_sign_days'] = sign_user_info.last_days
        result['last_days'] = sign_user_info.last_days % sign_config.cycle
        space_days = (datetime.date.today() - sign_user_info.newest_time).days if sign_user_info.newest_time else 0
        result['space_days'] = 0 if space_days <= 1 else space_days
        result['add_sign_number'] = sign_user_info.add_sign_number
        result['show_tip'] = sign_user_info.show_tips
        result['is_remind'] = sign_user_info.is_remind
        share_code = sign_user_info.share_code or 0

        month = str(share_code).replace(str(user_id), "")
        if (month and int(month) != datetime.date.today().month) or not month:
            sign_user_info.share_code = create_share_code(user_id=user_id)
            sign_user_info.add_sign_number = 0
        result['share_code'] = sign_user_info.share_code
        sign_user_info.save()

    return result


@bind("api/user/sign_user_data")
def get_sign_user_data(user_id=None):
    """获取用户签到数据"""
    result = {
        "real_prize": [],
    }

    prizes = SignBigPrizeV2.objects.filter(is_online=True).order_by("exchange_days")
    real_prize, prize_ids = [], []

    init_time = datetime.date.today()
    for item in prizes:
        prize_ids.append(item.id)
        init_time = item.online_time if init_time >= item.online_time else init_time
        real_prize.append({
            "id": item.id,
            "name": item.name,
            "count": item.count,
            "img_url": item.img_url,
            "can_exchanged": False,
            "need_days": item.exchange_days,
            "exchange_days": item.exchange_days,
            "has_exchanged": False,
            "online_time": item.online_time.strftime("%Y-%m-%d"),
            "total": item.init_count,
        })
    result['real_prize'] = real_prize

    if not user_id:
        return result

    user_id = int(user_id)
    exchanged_ids = list(ExchangedRecordV2.objects.filter(user_id=user_id).values_list("prize_id", flat=True))

    for item in result['real_prize']:
        if item['id'] in exchanged_ids:
            item['has_exchanged'] = True
        else:
            item['has_exchanged'] = False

    if not prizes:
        return result

    sign_logs = SignRecordLogV2.objects.filter(user_id=user_id, sign_time__gte=init_time)\
                                       .order_by("sign_time")\
                                       .values_list("sign_time", flat=True)

    reverse_sign_logs = list(sign_logs)[::-1]
    for item in result['real_prize']:
        temp_time = datetime.datetime.strptime(item['online_time'], '%Y-%m-%d')
        # if not item['count']:       #没有库存，不可兑换
        #     continue
        # if item['has_exchanged']:   #已兑换过
        #     continue

        max_length = handle_sign_date(online_time=temp_time.date(), sign_dates=list(sign_logs))
        lasts_length = handle_sign_length(reverse_sign_logs)
        item['can_exchanged'] = True if max_length >= item['exchange_days'] and not item['has_exchanged'] else False
        item['need_days'] = 0 if item['can_exchanged'] or lasts_length >= item['exchange_days']\
                              else item['exchange_days'] - lasts_length

    return result


@bind("api/user/calendar")
def sign_calendar(user_id=None, year=None, month=None):
    """签到日历"""
    MAX_ADD_SIGN_NUMBER = 3
    # user = get_user_from_context(ctx)
    if not user_id:
        return gen(CODES.MESSAGE_UNKNOWN_USER)

    year = datetime.date.today().year if not year else int(year)
    month = datetime.date.today().month if not month else int(month)

    if month < 12:
        month_days = (datetime.datetime(year=year, month=month+1, day=1) - datetime.datetime(year=year, month=month, day=1)).days
    else:
        month_days = (datetime.datetime(year=year+1, month=1, day=1) - datetime.datetime(year=year, month=month, day=1)).days

    start_time = datetime.date(year=year, month=month, day=1)

    end_time = datetime.date(year=year, month=month, day=month_days)

    sign_log = SignRecordLogV2.objects.filter(user_id=user_id, sign_time__gte=start_time, sign_time__lte=end_time)\
                                      .values("sign_time", "sign_type")
    change_status = {}
    for log in sign_log:
        change_status[log.get("sign_time")] = log.get("sign_type")
    config = SignConfigV2.objects.first()

    calender = []
    cache_key = record_user_special.format(user_id=user_id)
    read_special_list = sign_task_cache.lrange(cache_key, 0, -1)
    user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    if not user_info:
        user_info = SignUserInfoV2.objects.create(user_id=user_id, share_code=create_share_code(user_id=user_id))

    special_List = get_special(read_special_ids=read_special_list,
                               add_sign_chance=False if user_info.add_sign_number >= MAX_ADD_SIGN_NUMBER else True)

    for days in range(1, month_days+1):
        this_time = datetime.date(year=year, month=month, day=days)
        if not config or datetime.date(year=config.created_time.year, month=config.created_time.month,
                                       day=config.created_time.day) > this_time:
            calender.append({
                "sign_time": this_time.strftime("%Y-%m-%d"),
                "status": SIGN_CALENDAR_TYPE_V2.NO_START,   #未开启签到活动
            })
            continue

        if this_time > datetime.date.today():
            calender.append({
                "sign_time": this_time.strftime("%Y-%m-%d"),
                "status": SIGN_CALENDAR_TYPE_V2.CAN_NOT_SIGN,  # 无法签到  签到展示日期大于当前日期
            })
            continue

        if this_time in change_status:
            if change_status.get(this_time) == str(SIGN_TYPE_V2.GET_POINTS):
                status = SIGN_CALENDAR_TYPE_V2.GET_POINTS  #当天奖励的是美分
            elif change_status.get(this_time) == str(SIGN_TYPE_V2.GET_COUPON):
                status = SIGN_CALENDAR_TYPE_V2.GET_COUPON  #当天奖励的是券
            else:
                status = SIGN_CALENDAR_TYPE_V2.NOMALR_SIGN
            calender.append({
                "sign_time": this_time.strftime("%Y-%m-%d"),
                "status": status
            })
        elif this_time == datetime.date.today():
            calender.append({
                "sign_time": this_time.strftime("%Y-%m-%d"),
                "status": SIGN_CALENDAR_TYPE_V2.NO_START,  # 当天没有签到进入了签到页面
            })
        else:
            item = {}
            if special_List:
                rand_index = random.randint(0, len(special_List)-1)
                item = special_List[rand_index]
            calender.append({
                "sign_time": this_time.strftime("%Y-%m-%d"),
                "status": SIGN_CALENDAR_TYPE_V2.NO_SIGN,   # 断签
                "gm_url": item.get("gm_url"),
                "id": item.get("id"),
            })

    return calender


@bind("api/user/calendar_v2")
def sign_calendar(user_id=None, year=None, month=None):
    """签到日历"""
    if not user_id:
        return gen(CODES.MESSAGE_UNKNOWN_USER)

    year = datetime.date.today().year if not year else int(year)
    month = datetime.date.today().month if not month else int(month)

    if month < 12:
        month_days = (datetime.datetime(year=year, month=month+1, day=1) - datetime.datetime(year=year, month=month, day=1)).days
    else:
        month_days = (datetime.datetime(year=year+1, month=1, day=1) - datetime.datetime(year=year, month=month, day=1)).days

    start_time = datetime.date(year=year, month=month, day=1)

    end_time = datetime.date(year=year, month=month, day=month_days)

    sign_log = SignRecordLogV2.objects.filter(user_id=user_id, sign_time__gte=start_time, sign_time__lte=end_time)\
                                      .values("sign_time", "sign_type")

    exchange_log = ExchangedRecordV3.objects.filter(user_id=user_id, created_time__gte=start_time, created_time__lte=end_time)\
                                            .values("created_time")


    change_status = {}
    gift_status = {}
    calender = []
    for log in sign_log:
        change_status[log.get("sign_time")] = log.get("sign_type")

    # 过去未领取的礼物不展示，只展示过去已领取的礼物
    for gift in exchange_log:
        created_time = gift.get("created_time").date()
        gift_status[created_time] = 1

    # 展示未来3次可领礼物的时间
    sign_user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    last_days = sign_user_info.last_days
    has_sign = SignRecordLogV2.objects.filter(user_id=user_id, sign_time=datetime.datetime.now().date()).exists()

    if not has_sign:
        last_days = last_days + 1

    left_day = 10 - (last_days % 10)
    gift_date1 = datetime.datetime.now() + datetime.timedelta(days=left_day)
    gift_date2 = datetime.datetime.now() + datetime.timedelta(days=left_day + 10)
    gift_date3 = datetime.datetime.now() + datetime.timedelta(days=left_day + 10 + 10)

    gift_status[gift_date1.date()] = 1
    gift_status[gift_date2.date()] = 1
    gift_status[gift_date3.date()] = 1

    for days in range(1, month_days+1):
        this_time = datetime.date(year=year, month=month, day=days)
        day_sign_info = {
            "sign_time": this_time.strftime("%Y-%m-%d"),
            "status": SIGN_CALENDAR_TYPE_V2.NO_SIGN,
            "gift_status": SIGN_GIFT_STATUS.NO_GIFT
        }

        if this_time in gift_status:
            day_sign_info["gift_status"] = SIGN_GIFT_STATUS.RECEIVE

        if this_time in change_status:
            day_sign_info["status"] = SIGN_CALENDAR_TYPE_V2.NOMALR_SIGN

        calender.append(day_sign_info)
    return calender


@bind("api/user/add_sign_v2")
def add_sign(user_id=None, year=None, month=None, day=None, share_code=None):
    """补签"""

    MAX_ADD_SIGN_NUMBER = 3
    if not user_id and not share_code:
        return gen(CODES.MESSAGE_UNKNOWN_USER)

    if user_id and Doctor.objects.filter(user_id=user_id):
        return gen(CODES.IS_DOCTOR)  #机构号

    if share_code:
        sign_user = SignUserInfoV2.objects.filter(share_code=share_code).first()
        if not sign_user:
            raise GaiaRPCFaultException(
                error=ERROR.INVITE_CODE_ERROR,
                message=ERROR.getDesc(ERROR.INVITE_CODE_ERROR),
                data={}
            )   #分享码失效
        user_id = sign_user.user_id

    if not year or not month or not day:
        return gen(CODES.PARAMS_INCOMPLETE)

    add_time = datetime.date(year=int(year), month=int(month), day=int(day))
    config = SignConfigV2.objects.first()
    if not config or datetime.date(year=config.created_time.year, month=config.created_time.month,
                                   day=config.created_time.day) > add_time:
        return gen(CODES.DATA_SOURCE_NOT_CORRECT)

    sign_log = SignRecordLogV2.objects.filter(user_id=user_id, sign_time=add_time)
    if sign_log:
        return {"status": 1, "msg": u"已补签~"}

    user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    now_month = datetime.date.today().month
    if not user_info or \
            (user_info.updated_time and user_info.updated_time.month == now_month and user_info.add_sign_number >= MAX_ADD_SIGN_NUMBER):
        return {"status": 1, "msg": u"超过本月最大补签次数~"}

    SignRecordLogV2.objects.create(user_id=user_id, sign_time=add_time, sign_type=SIGN_TYPE_V2.ADD_SIGN)

    sign_log = SignRecordLogV2.objects.filter(user_id=user_id).order_by("-sign_time").values_list("sign_time", flat=True)

    last_length = handle_sign_length(sign_log)
    user_info.last_add_time = add_time
    user_info.add_sign_number += 1
    user_info.newest_time = user_info.newest_time if user_info.newest_time and add_time < user_info.newest_time else add_time
    user_info.last_days = last_length
    user_info.save()

    return {"status": 1, "msg": ""}


@bind("api/user/sign_exchanged_record")
def get_sign_record(user_id):
    result, prize_ids, days_prize_ids = {"record": []}, set(), set()
    if not user_id:
        return gen(CODES.MESSAGE_UNKNOWN_USER)
    new_records = SignUserExchangedPrize.objects.filter(user_id=user_id).values(
        'prize_id', 'express_no', 'created_time',
    )
    for record in new_records:
        prize_ids.add(record['prize_id'])
    prizes = SignBlindExchangePrize.objects.filter(id__in=prize_ids).values(
        'id', 'name', 'img_url',
    )
    prize_info = {prize['id']: prize for prize in prizes}
    for record in new_records:
        result['record'].append({
            "prize_name": prize_info[record['prize_id']].get('name', ''),
            "img_url": prize_info[record['prize_id']].get('img_url', ''),
            "exchanged_time": time.mktime(record['created_time'].timetuple()) * 1000,
            "press_no": record['express_no'] or "",
            "has_send": True if record['express_no'] else False
        })

    days_exchanged_record = ExchangedRecordV3.objects.filter(user_id=user_id).values("prize_id", "express_no", "created_time")
    for record in days_exchanged_record:
        days_prize_ids.add(record['prize_id'])
    prizes = SignPrizeV3.objects.filter(id__in=days_prize_ids).values(
        'id', 'name', 'img_url',
    )
    prize_info = {prize['id']: prize for prize in prizes}
    for record in days_exchanged_record:
        result['record'].append({
            "prize_name": prize_info[record['prize_id']].get('name', ''),
            "img_url": prize_info[record['prize_id']].get('img_url', ''),
            "exchanged_time": time.mktime(record['created_time'].timetuple()) * 1000,
            "press_no": record['express_no'] or "",
            "has_send": True if record['express_no'] else False
        })

    records = ExchangedRecordV2.objects.filter(user_id=user_id)
    if not records:
        result["record"].sort(key=lambda x: -x["exchanged_time"])
        return result

    for record in records:
        result['record'].append({
            "prize_name": record.prize.name,
            "img_url": record.prize.img_url,
            "exchanged_time": time.mktime(record.created_time.timetuple()) * 1000,
            "press_no": record.express_no or "",
            "has_send": True if record.express_no else False
        })

    sorted(result.get("record"), key=lambda x: x.get("exchanged_time"))

    return result


@bind("api/user/change_remind")
def change_remind(user_id, is_remind=False):
    if not user_id:
        return gen(CODES.MESSAGE_UNKNOWN_USER)

    sign_user, status = SignUserInfoV2.objects.get_or_create(user_id=user_id)
    sign_user.is_remind = True if int(is_remind) else False
    sign_user.share_code = create_share_code(user_id=user_id) if status else sign_user.share_code
    sign_user.save()

    return {"status": 1}


@bind("api/user/change_rush_remind")
def change_remind(user_id, is_remind=False):
    if not user_id:
        return gen(CODES.MESSAGE_UNKNOWN_USER)

    sign_user, status = SignUserInfoV2.objects.get_or_create(user_id=user_id)
    sign_user.rush_remind = True if int(is_remind) else False
    sign_user.share_code = create_share_code(user_id=user_id) if status else sign_user.share_code
    sign_user.save()

    return {"status": 1}


@bind("api/user/sign_xcx_form_id")
def get_xcx_form_id(form_id, user_id):
    if not user_id:
        return gen(CODES.MESSAGE_UNKNOWN_USER)
    if not form_id:
        return

    sign_user, status = SignUserInfoV2.objects.get_or_create(user_id=user_id)
    sign_user.xcx_form_id = form_id
    sign_user.share_code = create_share_code(user_id=user_id) if status else sign_user.share_code
    sign_user.save()

    return {"status": 1}


@bind("api/user/sign_prize_detail")
def get_sign_prize_detail(prize_id, user_id):
    if not prize_id:
        return gen(CODES.PARAMS_INVALID)
    try:
        prize_info = SignBlindExchangePrize.objects.get(id=prize_id, is_online=True)
    except SignBlindExchangePrize.DoesNotExist:
        return {}
    exchanged_count = SignUserExchangedPrize.objects.filter(prize_id=prize_id).count()
    blind_box_ids = prize_info.blind_box_list
    result = {
        'id': prize_id,
        'name': prize_info.name,
        'detail_introduce': prize_info.detail_introduce,
        'detail_img': prize_info.detail_img,
        'count': prize_info.count,
        'exchanged_count': exchanged_count + random.randint(10, 20),
    }

    card_info = SignBlindBox.objects.filter(id__in=blind_box_ids).values('id', 'is_final', 'name', 'img_url')
    blind_box_is_final_dic = {card['id']: card for card in card_info}
    user_get_blind_box = {}
    if user_id:
        user_box = SignUserBlindBox.objects.filter(
            user_id=user_id).values('blind_prize_id', 'count')
        user_get_blind_box.update({card['blind_prize_id']: card['count'] for card in user_box})

    result.update({
        'blind_box_info': [{
            'id': _id,
            'is_final': blind_box_is_final_dic[_id].get('is_final', False),
            'name': blind_box_is_final_dic[_id].get('name', ''),
            'img_url': blind_box_is_final_dic[_id].get('img_url', ''),
            'get_count': user_get_blind_box.get(_id, 0),
        } for _id in blind_box_ids]
    })

    return result


@bind("api/user/luck_draw")
def luck_draw(user_id):
    """用户抽取盲盒的操作"""
    sign_user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    if not sign_user_info or sign_user_info.points_count < LuckDrawCost:
        return gen(CODES.SIGN_NO_POINTS)

    probability_list = SignBlindBox.objects.filter(is_online=True).order_by("id").values_list("probability", flat=True)
    if not probability_list:
        return gen(CODES.SIGN_NO_BLIND_BOX)
    list_sum = sum(list(probability_list))
    rand_int = random.randint(0, list_sum)
    temp_sum, hit_index = 0, 0
    for index, item in enumerate(probability_list):
        if temp_sum <= rand_int < (temp_sum + item):
            hit_index = index
            break
        temp_sum += item

    all_blind_box = list(SignBlindBox.objects.filter(is_online=True).order_by("id").values_list("id", flat=True))
    item, status = SignUserBlindBox.objects.get_or_create(user_id=user_id, blind_prize_id=all_blind_box[hit_index])
    if not status:
        item.count += 1
        item.save()

    sign_user_info.points_count -= LuckDrawCost
    sign_user_info.save()
    info_logger.info(u"sign_exchange_{user_id}_{card_id}_time={hour}--{minute}".format(user_id=user_id,
                                                                            card_id=all_blind_box[hit_index],
                                                                            hour=datetime.datetime.now().hour,
                                                                            minute=datetime.datetime.now().minute))

    return {"blind_box_id": all_blind_box[hit_index]}

@bind("api/sign/get_user_data")
def sign_get_user_data(user_id):
    if not user_id:
        return

    user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    if not user_info:
        return {}
    month, year = datetime.datetime.now().month, datetime.datetime.now().year
    last_sign_month = user_info.updated_time and user_info.updated_time.month or 0
    last_sign_year = user_info.updated_time and user_info.updated_time.year or 0
    if year != last_sign_year or last_sign_month != month:
        user_info.add_sign_number = 0
        user_info.share_code = create_share_code(user_id=user_id)
        user_info.save()

    return {
        "is_remind": user_info.is_remind,
        "user_id": user_id,
        "add_sign_number": user_info.add_sign_number,
        "share_code": user_info.share_code,
    }


@bind("api/user/sign/get_user_data")
def get_base_data(user_id):
    """签到详情页用户数据"""
    result = {
        "last_days": 0,
        "sign_status": 0,
        "points_count": 0,
        "rule": "",
        "blind_rule": "",
        "special_list": [],
        "task_rate": {},
        "step_points": 5,
        "draw_points": LuckDrawCost,
        "rush_remind": False,
        "friend_assist_img": "",
        "new_user": False,
        "share_click_state": True,
        "has_adress": False,
        "is_remind": False,

    }
    assist_record = SignAssistUser.objects.filter(user_id=user_id)
    if assist_record:
        result['share_click_state'] = False if assist_record else True

    sign_config = SignConfigV2.objects.first()
    if not sign_config:
        return result

    result['blind_rule'] = sign_config.prize
    result['rule'] = sign_config.rule
    result['friend_assist_img'] = sign_config.friend_assist_img_url
    special_list = json.loads(sign_config.operate_config)
    special_list = [item for item in special_list if item.get('gm_url')]

    task_records = SignTaskUserFinish.objects.filter(task_type=9, user_id=user_id,
                                                     finish_time=datetime.datetime.today()) \
                                             .values_list("task_value", flat=True)

    result["task_records"] = list(task_records)
    result["special_list"] = special_list
    result["step_points"] = sign_config.cycle
    if not user_id:
        return result

    sign_user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    if not sign_user_info:
        sign_user_info = SignUserInfoV2.objects.create(user_id=user_id, share_code=create_share_code(user_id=user_id),
                                                       show_tips=True)

    # 产品规定日期
    set_date = datetime.date(year=2019, month=10, day=18)
    show_rule = True if datetime.date.today() >= set_date else False
    result['new_user'] = True if sign_user_info.show_tips and show_rule else False
    if sign_user_info.show_tips:
        sign_user_info.show_tips = False
        sign_user_info.save()

    result['rush_remind'] = sign_user_info.rush_remind or False
    if sign_user_info.newest_time and datetime.date.today() == sign_user_info.newest_time:
        result['sign_status'] = SIGN_TYPE_V2.NOMALR_SIGN  # 用户已签到
    elif sign_user_info.newest_time and datetime.date.today() == (
            sign_user_info.newest_time + datetime.timedelta(days=1)):
        result['sign_status'] = SIGN_CALENDAR_TYPE_V2.CAN_NOT_SIGN  # 当天还未签到
    elif not sign_user_info.newest_time:
        result['sign_status'] = SIGN_CALENDAR_TYPE_V2.CAN_NOT_SIGN  # 第一次签到，还未签到
    else:
        result['sign_status'] = SIGN_CALENDAR_TYPE_V2.NO_SIGN  # 断签了

    today = datetime.datetime.now().date()
    yesterday = today - datetime.timedelta(days=1)
    if sign_user_info.last_days > 0 and sign_user_info.newest_time not in [today, yesterday]:
        sign_user_info.last_days = 0
        sign_user_info.save()

    result.update({
        "last_days": sign_user_info.last_days,
        "points_count": sign_user_info.points_count,
    })

    task_rate = {'browse': 0,    #逛商品
                 'pay_order': 0,    #下单
                 'friend_assist': 0,    #好友助力
                 'scan_face': 0,    #扫脸
                 'sacn_skin': 0,    #测肤
                 'download': 0,    #下载
                 'old_assist': 0,  #老版本好友助力
                 'browse_special': 0, #逛专题
                 }
    #获取用户任务完成数据
    every_day_task = SignTaskUserFinish.objects.filter(user_id=user_id, task_type__in=[1, 2, 3, 7, 9], finish_time=datetime.date.today())
    once_task = SignTaskUserFinish.objects.filter(user_id=user_id, task_type__in=[4, 5, 6])
    for task in (every_day_task | once_task):
        key_value = task_to_mark.get(str(task.task_type))
        task_rate[key_value] += 1
    result["task_rate"] = task_rate
    from api.tool.user_tool import get_user_extra_by_user_id
    user_extra = get_user_extra_by_user_id(user_id=user_id)
    result['has_adress'] = True if user_extra and user_extra.address else False
    result["is_remind"] = sign_user_info.is_remind
    return result


@bind("api/user/sign/get_prize_data")
def get_prize_data(user_id):
    """
    盲盒卡片以及奖品数据
    """
    result = {
        "blind_box_list": [],
        "time_countdown": 0,
        "real_prizes": [],
    }
    blind_box_list, blind_box_dic, real_prizes = [], {}, []
    blind_boxes = SignBlindBox.objects.filter(is_online=True).order_by("show_order", "id")
    user_card_record = SignUserBlindBox.objects.filter(user_id=user_id)
    blind_record_data = {}
    for record in user_card_record:
        blind_record_data[str(record.blind_prize_id)] = record.count

    for blind_card in blind_boxes:
        item = {
            "id": blind_card.id,
            "name": blind_card.name,
            "img_url": blind_card.img_url,
            "count": blind_record_data.get(str(blind_card.id)) or 0,
            "is_final": blind_card.is_final,
        }
        blind_box_list.append(item)
        blind_box_dic[str(blind_card.id)] = item

    result['blind_box_list'] = blind_box_list
    blind_box_ids = list(SignUserBlindBox.objects.filter(user_id=user_id, count__gt=0).values_list("blind_prize_id", flat=True))

    sign_prizes = SignBlindExchangePrize.objects.filter(is_online=True).order_by("show_order", "id")
    exchanged_prize = SignUserExchangedPrize.objects.filter(user_id=user_id)
    exchanged_prize_dic = {}
    #     2----已兑换    3----填写地址        1----可以兑换    0------不可以兑换
    for ex_prize in exchanged_prize:
        if not ex_prize.check_adress:
            exchanged_prize_dic[str(ex_prize.prize_id)] = 3
        if ex_prize.check_adress:
            exchanged_prize_dic[str(ex_prize.prize_id)] = 2

    for prize in sign_prizes:
        if str(prize.id) in exchanged_prize_dic:
            exchanged_status = exchanged_prize_dic.get(str(prize.id))
        else:
            exchanged_status = 1 if judge_prize_exchanged(have_blind_ids=blind_box_ids,
                                                          prize_blind_ids=prize.blind_box_list) else 0
        if datetime.datetime.now().hour < RushBuyHour:
            exchanged_status = 0

        rush_cache_count = rush_cache_key + u"_{prize_id}_count".format(prize_id=prize.id)
        prize_blind_box_list = [blind_box_dic.get(str(item)) or {} for item in prize.blind_box_list]

        prize_is_final = False
        for box in prize_blind_box_list:
            if box.get("is_final"):
                prize_is_final = True
        prize_left_count = prize.count - int(sign_rush_cache.get(rush_cache_count) or 0)
        prize_item = {
            "id": prize.id,
            "name": prize.name,
            "img_url": prize.img_url,
            "count": prize.count,
            "description": prize.description,
            "exchanged_status": exchanged_status,
            "left_count": prize_left_count if prize_left_count >= 0 else 0,
            "need_bind_box": prize_blind_box_list
        }
        if prize_is_final:
            real_prizes.insert(0, prize_item)
        else:
            real_prizes.append(prize_item)

    result['real_prizes'] = real_prizes
    if RushBuyHour > datetime.datetime.now().hour:
        rush_buy_time = datetime.datetime(year=datetime.datetime.now().year,
                                          month=datetime.datetime.now().month,
                                          day=datetime.datetime.now().day,
                                          hour=RushBuyHour)
    else:
        rush_buy_time = datetime.datetime(year=datetime.datetime.now().year,
                                          month=datetime.datetime.now().month,
                                          day=datetime.datetime.now().day,
                                          hour=RushBuyHour) + datetime.timedelta(days=1)

    result['time_countdown'] = int(int(time.mktime(rush_buy_time.timetuple())) - time.time())
    return result


@bind("api/sign/rush_prize")
def rush_prize(user_id, prize_id, is_check=True):
    """签到抢购商品"""

    if datetime.datetime.now().hour < RushBuyHour:
        return gen(CODES.SIGN_RUSH_PRIZE_NO_ONTIME)

    rush_prize = SignBlindExchangePrize.objects.filter(id=prize_id).first()
    if not rush_prize:
        return gen(CODES.SIGN_ZERO_PRIZE_COUNT)

    exchanged_record = SignUserExchangedPrize.objects.filter(user_id=user_id, prize_id=prize_id)
    if exchanged_record:
        return gen(CODES.SIGN_HAS_EXCHANGED)

    rush_cache_count = rush_cache_key + u"_{prize_id}_count".format(prize_id=prize_id)
    rush_len = int(sign_rush_cache.get(rush_cache_count) or 0)
    if rush_len >= rush_prize.count:
        return gen(CODES.SIGN_ZERO_PRIZE_COUNT)

    blind_list = list(SignUserBlindBox.objects.filter(user_id=user_id, count__gt=0).values_list('blind_prize_id', flat=True))
    blind_list = list(set(blind_list))

    Qualifications = True
    for item in rush_prize.blind_box_list:
        if item not in blind_list:
            Qualifications = False
            break

    if not Qualifications:
        return gen(CODES.SIGN_NO_QUALIFICATION)

    #   再次确定可插入队列
    rush_len = int(sign_rush_cache.get(rush_cache_count) or 0)
    if rush_len >= rush_prize.count:
        return gen(CODES.SIGN_ZERO_PRIZE_COUNT)
    info_logger.info(u"签到兑换记录----{user_id}-----{prize_id}".format(user_id=user_id, prize_id=prize_id))

    sign_rush_cache.incr(rush_cache_count)
    # sign_rush_cache.rpush(rush_cache_prize, cache_data)
    # sign_rush_cache.expire(rush_cache_prize, rush_cache_expire_time)
    sign_rush_cache.expire(rush_cache_count, rush_cache_expire_time)

    #异步处理兑换
    sign_rush_prize.delay(user_id=user_id, prize_id=prize_id, is_check=is_check)
    return {"status": 1}


@bind("api/sign/finish_task")
def complete_task(user_id, task_type, task_value=None):
    if task_type == SIGN_TASK_TYPE.FRIEND_ASSIST:
        finish_tasks = SignTaskUserFinish.objects.filter(
            user_id=user_id, task_type=SIGN_TASK_TYPE.OLD_FRIEND_ASSIST, finish_time=datetime.date.today())
        limit_count, add_points = task_limit_everyday.get(str(SIGN_TASK_TYPE.OLD_FRIEND_ASSIST))
        task_type = SIGN_TASK_TYPE.OLD_FRIEND_ASSIST
    else:
        finish_tasks = SignTaskUserFinish.objects.filter(
            user_id=user_id, task_type=task_type, finish_time=datetime.date.today())
        limit_count, add_points = task_limit_everyday.get(str(task_type))

    if len(list(finish_tasks)) >= limit_count:
        return gen(CODES.SIGN_TASK_DONE)

    if task_type == SIGN_TASK_TYPE.PAY_ORDER:
        wait_order_key = u"sign_task_cache:sign_order_{user_id}".format(user_id=user_id)
        # wait_order_key = u"sign_order_{user_id}__{task_value}".format(user_id=user_id, task_value=task_value)
        ex = sign_task_cache.ttl(wait_order_key)
        ex_time = ex if ex != -2 else 24 * 60 * 60
        with sign_task_cache.pipeline() as pipeline:
            pipeline.sadd(wait_order_key, task_value)
            pipeline.expire(wait_order_key, ex_time)
            pipeline.execute()
        return {"status": 1}

    elif task_type == SIGN_TASK_TYPE.BROWSE:
        now_date = datetime.datetime.today()
        # 过期时间截止到当天 24 点
        task_record = SignTaskUserFinish.objects.filter(user_id=user_id, task_type=int(task_type), task_value=task_value,
                                                        finish_time=datetime.date.today())
        if task_record:
            return gen(CODES.SIGN_TASK_DONE)

        expire_time = int((now_date.replace(hour=0, minute=0, second=0) - now_date).seconds)
        cache_key = browse_service_cache_key.format(user_id=user_id)
        service_cache_len = sign_task_cache.scard(cache_key)
        if service_cache_len == 0:
            sign_task_cache.sadd(cache_key, task_value)
            sign_task_cache.expire(cache_key, expire_time)
        elif service_cache_len < 10:
            sign_task_cache.sadd(cache_key, task_value)
        else:
            return

    elif task_type == SIGN_TASK_TYPE.DOWNLOAD:
        wait_download_key = u"{user_id}__download".format(user_id=user_id)
        sign_task_cache.set(wait_download_key, 1)
        return {"status": 1}

    if int(task_type) == 9:
        special_item = SignTaskUserFinish.objects.filter(user_id=user_id, task_type=int(task_type), task_value=task_value,
                                                         finish_time=datetime.date.today())
        if special_item:
            return {"status": 1}

        limit_count, add_points = task_limit_everyday.get("9")

    task_value = task_value if task_value else ""
    SignTaskUserFinish.objects.create(user_id=user_id, task_type=int(task_type), task_value=task_value,
                                      finish_time=datetime.date.today())
    user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    if not user_info:
        user_info = SignUserInfoV2.objects.create(user_id=user_id, share_code=create_share_code(user_id))
    user_info.points_count += add_points
    user_info.save()

    return {"status": 1}


@bind("api/sign/friend_assist")
def friend_help(user_id, assist_user_id):
    """
    好友助力
    :param user_id: 当前用户ID
    :param assist_user_id: 受帮助的用户ID
    :return:
    """
    assist_record = SignAssistUser.objects.filter(user_id=user_id)
    if assist_record:
        return {"assist_number": len(assist_record), "msg": u"你已成功为好友助力！"}

    if user_id == assist_user_id:
        return {"assist_number": len(assist_record), "msg": u"你的本次助力没有成功哦，快喊其他小伙伴来帮你助力吧！"}

    limit_count, add_points = task_limit_everyday.get(str(3))
    task_count = SignTaskUserFinish.objects.filter(user_id=assist_user_id, task_type=SIGN_TASK_TYPE.FRIEND_ASSIST,
                                                   finish_time=datetime.date.today()).count()
    if task_count >= limit_count:
        return {"assist_number": len(assist_record), "msg": u"今天助力次数已达上限，明天再来吧！"}

    SignAssistUser.objects.create(assist_user_id=assist_user_id, user_id=user_id)

    SignTaskUserFinish.objects.create(user_id=assist_user_id, task_type=SIGN_TASK_TYPE.FRIEND_ASSIST,
                                      finish_time=datetime.date.today())

    user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    assist_user_info = SignUserInfoV2.objects.filter(user_id=assist_user_id).first()
    if not user_info:
        user_info = SignUserInfoV2.objects.create(user_id=user_id, share_code=create_share_code(user_id))
    if not assist_user_info:
        assist_user_info = SignUserInfoV2.objects.create(user_id=assist_user_id, share_code=create_share_code(assist_user_id))
    user_info.points_count += add_points
    user_info.save()
    assist_user_info.points_count += add_points
    assist_user_info.save()

    return {"assist_number": len(assist_record) + 1, "msg": ""}


@bind_context('api/sign/recommend_services')
def sign_recommend_service_list(
        ctx, current_city_id=None, start_num=0, size=10, device_id=None,
        request_from=SERVICE_DISPLAY_PORT.APP
):
    """
    签到推荐美购 app、小程序共用此接口
    :return:
    """
    valid_service_ids, city_tag_id, services = [], None, {}
    user = get_user_from_context(ctx)
    if not user:
        return gen(CODES.LOGIN_REQUIRED)

    if current_city_id:
        _, city_tag_id = get_location_tag_id_by_city_id(current_city_id)

    rpc_client = get_rpc_remote_invoker()
    try:
        rs = rpc_client['doris/hera/in_city_whitelist'](city_ids=[current_city_id, ]).unwrap()
        in_whitelist = int(bool(rs))
    except:
        in_whitelist = 0

    query_params = {
        "in_whitelist": in_whitelist,
        "user_city_tag_id": city_tag_id,
        "size": size,
        'user_id': user.id,
        'device_id': device_id or '0',
    }
    if request_from == SERVICE_DISPLAY_PORT.APP:
        try:
            services = rpc_client['doris/recommend/views/check_in'](
                query_params=query_params,
            ).unwrap()
        except:
            logging_exception()
    elif request_from == SERVICE_DISPLAY_PORT.XCX:
        query_params.update({
            'offset': start_num,
        })
        try:
            services = rpc_client['doris/recommend/views/wechat_check_in'](
                query_params=query_params,
            ).unwrap()
        except:
            logging_exception()

    recommend_service_ids = services.get("service_ids", [])

    services_info_dic = get_toc_spu_info_list_mapping_by_spu_ids(recommend_service_ids)
    recommend_services = [services_info_dic[str(service_id)]
                          for service_id in recommend_service_ids if str(service_id) in services_info_dic]
    from rpc.tool.protocol import gm_protocol
    sign_config = SignConfigV2.objects.first()
    stay_seconds = sign_config.browse_add_points if sign_config else 10
    service_task_status = get_service_browse_task_status(user_id=user.id, service_ids=recommend_service_ids)
    for service in recommend_services:
        has_task = 1 if service_task_status.get(str(service['service_id'])) else 0
        if request_from == SERVICE_DISPLAY_PORT.APP:
            service['gm_url'] = gm_protocol.get_service_detail(
                id=service['service_id'], has_task=has_task, sign_task_seconds=stay_seconds, sign_points=20,
                transparent_key='rm_r63bkpbh_1'
            )
        elif request_from == SERVICE_DISPLAY_PORT.XCX:
            service['gm_url'] = u"/packageTrade/pages/welfare/detail/detail?" \
                                u"welfare_id={service_id}&type=common&sign_task_time={stay_seconds}".format(
                service_id=service['service_id'], stay_seconds=stay_seconds)
    return {
        'recommend_services': recommend_services,
    }


@bind("api/sign/check_adress")
def check_adress(user_id, prize_id):
    if not user_id or not prize_id:
        return {}

    record = SignUserExchangedPrize.objects.filter(user_id=user_id, prize_id=prize_id).first()
    if not record:
        return

    record.check_adress = True
    record.save()

    return


@bind('api/sign_finish/alert')
def sign_task_alert(user_id):
    # PM乱加 代码需优化
    result = []
    if not user_id:
        return {}

    for _type, desc in SIGN_TASK_TYPE:
        _, points = task_limit_everyday.get(str(_type)) or (0, 0)
        tasks_count = SignTaskUserFinish.objects.filter(user_id=user_id, task_type=_type, is_read=False).count()
        result.append({
            'task_type': _type,
            'add_points': points * tasks_count,
        })

    other_task = {
        "task_type": SIGN_TASK_TYPE.SCAN_FACE, "add_points": 0,
        'name': alert_message.get(str(SIGN_TASK_TYPE.SCAN_FACE))}
    assist_task = {
        "task_type": SIGN_TASK_TYPE.FRIEND_ASSIST, "add_points": 0,
        'name': alert_message.get(str(SIGN_TASK_TYPE.FRIEND_ASSIST))}
    temp_result = []

    for item in result:
        if not item.get("add_points"):
            continue
        if item.get("task_type") in [SIGN_TASK_TYPE.SCAN_FACE, SIGN_TASK_TYPE.SCAN_SKIN, SIGN_TASK_TYPE.DOWNLOAD]:
            _, points = task_limit_everyday.get(str(item.get("task_type")))
            other_task['add_points'] += item.get("add_points")
        elif item.get("task_type") in [SIGN_TASK_TYPE.FRIEND_ASSIST, SIGN_TASK_TYPE.OLD_FRIEND_ASSIST]:
            _, points = task_limit_everyday.get(str(item.get("task_type")))
            assist_task['add_points'] += item.get("add_points")
        else:
            item['name'] = alert_message.get(str(item.get('task_type')))
            temp_result.append(item)

    task_count = SignTaskUserFinish.objects.filter(user_id=user_id, task_type=9, is_read=False).count()
    if task_count:
        temp_result.append({
            "name": alert_message.get("9"),
            "tas_type": 9,
            "add_points": task_count * 20,
        })

    if assist_task.get("add_points"):
        temp_result.append(assist_task)
    if other_task.get("add_points"):
        temp_result.append(other_task)

    SignTaskUserFinish.objects.filter(user_id=user_id, is_read=False).update(is_read=True)
    return {
        'result': temp_result,
    }


@bind("api/sign/download_task")
def complate_download_task(user_id):
    if not user_id:
        return
    wait_download_key = u"{user_id}__download".format(user_id=user_id)
    xcx_download = sign_task_cache.get(wait_download_key)
    if not xcx_download:
        return

    task_record = SignTaskUserFinish.objects.filter(user_id=user_id, task_type=SIGN_TASK_TYPE.DOWNLOAD)
    if task_record:
        return

    user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()
    user_info.points_count += 50
    user_info.show_point += 50
    user_info.save()
    SignTaskUserFinish.objects.create(user_id=user_id, task_type=SIGN_TASK_TYPE.DOWNLOAD)


@bind("api/sign/record_special")
def calendar_record_special(user_id, special_id):
    now_date = datetime.datetime.today()
    expire_time = int((now_date.replace(hour=0, minute=0, second=0) - now_date).seconds)
    cache_key = record_user_special.format(user_id=user_id)
    sign_task_cache.lpush(cache_key, special_id)
    sign_task_cache.expire(cache_key, expire_time)


def handle_prize_exchange(user_id, prize_id):
    # return的值  0--不可以兑换  1--可以兑换  2--已兑换  3--已过期
    prize = SignPrizeV3.objects.filter(id=prize_id).first()
    exchange_records = ExchangedRecordV3.objects.filter(user_id=user_id, prize_id=prize_id)

    sign_logs = SignRecordLogV2.objects.filter(user_id=user_id,
                                               sign_time__gte=start_prize_time) \
        .order_by("sign_time")

    time_list, temp, last_day, add_time = [], None, 0, datetime.date(year=2019, month=10, day=25)
    newest_time = None

    for sign_log in sign_logs:
        created_time = sign_log.created_time.date()
        add_time = created_time if sign_log.sign_type == SIGN_TYPE_V2.ADD_SIGN and created_time > add_time else add_time
        if not temp:
            temp = sign_log.sign_time
            last_day = 1
            newest_time = max(sign_log.sign_time, add_time)
            continue

        if temp == (sign_log.sign_time + datetime.timedelta(days=-1)):
            last_day += 1
            if last_day == prize.exchange_days:
                newest_time = max(sign_log.sign_time, add_time)
        else:
            if last_day >= prize.exchange_days:
                time_list.append({
                    "last_days": last_day,
                    "newest_time": newest_time,
                })
            last_day, add_time, newest_time = 1, datetime.date(year=2019, month=10, day=25), sign_log.sign_time
        temp = sign_log.sign_time

    if last_day >= prize.exchange_days:
        time_list.append({
            "last_days": last_day,
            "newest_time": newest_time,
        })

    last_time = time_list[-1].get("newest_time") if time_list else datetime.date.today()
    if len(time_list) <= len(exchange_records):
        if exchange_records.last() and exchange_records.last().created_time.date() >= last_time:
            return 2
        else:
            return 0

    can_exchange_time = []
    for item in time_list:
        has_exchanged = False
        for record in exchange_records:
            if item.get("newest_time") <= record.created_time.date() <= item.get("newest_time") + datetime.timedelta(
                    days=6):
                has_exchanged = True
                break

        if item.get("newest_time") < datetime.date.today() + datetime.timedelta(days=-6):
            has_exchanged = True

        if not has_exchanged:
            can_exchange_time.append(item)

    if not can_exchange_time and exchange_records.last() and exchange_records.last().created_time.date() >= last_time:
        return 2

    if not can_exchange_time:
        return 0

    return 1


def handle_prize_exchange_v2(user_id, prize_id, last_lenth, sign_status):
    # return的值  0--不可以兑换  1--可以兑换  2--已兑换  3--已过期
    OVERDUE_TIME = 7
    turns = last_lenth % 30
    prize = SignPrizeV3.objects.filter(id=prize_id).first()
    if sign_status != SIGN_CALENDAR_TYPE_V2.NO_SIGN and turns == 0 and last_lenth >= 30:
        turns = 30

    turn_start_time = datetime.datetime.now() - datetime.timedelta(days=turns)
    exchange_records = ExchangedRecordV3.objects.filter(user_id=user_id,
                                                        prize_id=prize_id,
                                                        created_time__gt=turn_start_time).first()
    if exchange_records:
        return PRIZE_STATUS.EXCHANGED
    if not prize or prize.exchange_days > turns:
        return PRIZE_STATUS.CANT_EXCHANGE
    if turns - OVERDUE_TIME > prize.exchange_days:
        return PRIZE_STATUS.OVERDUE
    return PRIZE_STATUS.CAN_EXCHANGE


@bind("api/user/sign_real_list")
def get_sign_real_list(user_id):
    prize_list = SignPrizeV3.objects.filter(is_online=True)
    result = []

    records = list(SignRecordLogV2.objects.filter(user_id=user_id,
                                                  sign_time__gte=start_prize_time,
                                                  sign_time__lte=datetime.date.today())
                   .order_by("-sign_time")
                   .values_list("sign_time", flat=True))
    last_lenth = handle_sign_length(records)

    sign_user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()

    if sign_user_info and sign_user_info.newest_time and datetime.date.today() == sign_user_info.newest_time:
        sign_status = SIGN_TYPE_V2.NOMALR_SIGN  # 用户已签到
    else:
        sign_status = SIGN_CALENDAR_TYPE_V2.NO_SIGN  # 断签了

    for prize in prize_list:
        result.append({
            "id": prize.id,
            "name": prize.name,
            "need_days": prize.exchange_days,
            "img_url": prize.img_url,
            "count": prize.count,
            "exchanged_status": handle_prize_exchange_v2(user_id=user_id, prize_id=prize.id,
                                                         last_lenth=sign_user_info and sign_user_info.last_days or 0,
                                                         sign_status=sign_status),
            "last_days": last_lenth,
        })

    return result


@bind("api/user/get_sign_msg")
def get_sign_msg(user_id):
    """
    后续还要改
    :param user_id:
    :return:
    """
    if not user_id or datetime.date.today() < start_prize_time:
        return

    yestday = datetime.date.today() + datetime.timedelta(days=-1)
    records = list(SignRecordLogV2.objects.filter(user_id=user_id,
                                                  sign_time__gte=start_prize_time,
                                                  sign_time__lt=datetime.date.today())
                                          .order_by("-sign_time")
                                          .values_list("sign_time", flat=True))
    if len(records) and records[0] == yestday:
        last_lenth = handle_sign_length(records) + 1
    else:
        last_lenth = 1

    prize_list = SignPrizeV3.objects.filter(is_online=True).order_by("exchange_days")
    if not prize_list:
        return ""

    sign_msg = u""

    last_lenth = (last_lenth % prize_list.last().exchange_days) if prize_list.last() and last_lenth > prize_list.last().exchange_days else last_lenth
    for index in range(len(prize_list)):

        if last_lenth < prize_list[index].exchange_days:
            need_day = prize_list[index].exchange_days - last_lenth
            sign_msg = u"再签{need_day}天拿{prize_name}".format(prize_name=prize_list[index].name,
                                                               need_day=need_day)
            break

    return sign_msg


@bind("api/sign/exchange_prize")
def exchange_prize(user_id, prize_id):

    if not user_id or not prize_id:
        return {"msg": u"参数不完整"}

    prize = SignPrizeV3.objects.filter(id=prize_id).first()
    if not prize:
        return {"msg": u"奖品不存在"}

    if not prize.count:
        return {"msg": u"奖品库存不足"}

    exchange_records = ExchangedRecordV3.objects.filter(user_id=user_id, prize_id=prize_id)

    sign_logs = SignRecordLogV2.objects.filter(user_id=user_id,
                                               sign_time__gte=start_prize_time)\
                                       .order_by("sign_time")

    time_list, temp, last_day, add_time = [], None, 0, datetime.date(year=2019, month=10, day=25)
    newest_time = None
    for sign_log in sign_logs:
        created_time = sign_log.created_time.date()
        add_time = created_time if sign_log.sign_type == SIGN_TYPE_V2.ADD_SIGN and created_time > add_time else add_time
        if not temp:
            temp = sign_log.sign_time
            last_day = 1
            newest_time = max(sign_log.sign_time, add_time)
            continue

        if temp == (sign_log.sign_time + datetime.timedelta(days=-1)):
            last_day += 1
            if last_day == prize.exchange_days:
                newest_time = max(sign_log.sign_time, add_time)
            temp = sign_log.sign_time
        else:
            if last_day >= prize.exchange_days:
                time_list.append({
                    "last_days": last_day,
                    "newest_time": newest_time,
                })
            temp, last_day, add_time, newest_time = sign_log.sign_time, 1, datetime.date(year=2019, month=10, day=25), sign_log.sign_time

    if last_day >= prize.exchange_days:
        time_list.append({
            "last_days": last_day,
            "newest_time": newest_time,
        })

    if len(time_list) <= len(exchange_records):
        return {"msg": u"没有机会了"}

    can_exchange_time = []
    for item in time_list:
        has_exchanged = False
        for record in exchange_records:
            if item.get("newest_time") <= record.created_time.date() <= item.get("newest_time") + datetime.timedelta(days=6):
                has_exchanged = True
                break

        if item.get("newest_time") < datetime.date.today() + datetime.timedelta(days=-6):
            has_exchanged = True

        if not has_exchanged:
            can_exchange_time.append(item)

    if not can_exchange_time:
        return {"msg": u"没有机会了"}

    ExchangedRecordV3.objects.create(user_id=user_id, prize_id=prize_id)
    prize.count -= 1
    prize.save()

    return {"status": 1}


@bind("api/sign/exchange_prize_v2")
def exchange_prize_v2(user_id, prize_id):

    if not user_id or not prize_id:
        return {"msg": u"参数不完整"}

    prize = SignPrizeV3.objects.filter(id=prize_id).first()
    if not prize:
        return {"msg": u"奖品不存在"}

    if not prize.count:
        return {"msg": u"奖品库存不足"}

    sign_user_info = SignUserInfoV2.objects.filter(user_id=user_id).first()

    if sign_user_info.newest_time and datetime.date.today() == sign_user_info.newest_time:
        sign_status = SIGN_TYPE_V2.NOMALR_SIGN  # 用户已签到
    else:
        sign_status = SIGN_CALENDAR_TYPE_V2.NO_SIGN  # 断签了

    status = handle_prize_exchange_v2(user_id, prize_id, sign_user_info.last_days, sign_status)
    if status != PRIZE_STATUS.CAN_EXCHANGE:
        return {"msg": u"没有机会了"}

    ExchangedRecordV3.objects.create(user_id=user_id, prize_id=prize_id)
    prize.count -= 1
    prize.save()

    return {"status": 1}


@bind('api/region/by_city_id')
def get_region_id_by_city_id(city_id=None):
    return get_region_by_city_id(city_id=city_id)


@bind('api/region/visual')
def get_all_region_for_visual():
    from api.models.area import Region
    return list(Region.objects.filter().values('id', 'name'))


@bind('api/new_special_info')
def get_new_special_by_region_id(region_id, special_ids):
    """
    根据大区id筛选 专题
    :param region_id:
    :param special_ids:
    :return:
    """
    result = {}
    if not all([region_id, special_ids]):
        return result

    valid_special_ids = SpecialRegion.filter_special_by_region_id(
        region_id=region_id, special_id_list=special_ids,
    )
    special_list = Special.get_special_info_by_ids(special_ids=valid_special_ids)
    result['specials'] = special_list

    return result


@bind('api/get_url_with_task_info')
def get_service_url(platform, service_ids, user_id=None):
    """
    处理美购的更没协议，加上签到任务参数
    :param platform:
    :param user_id:
    :param service_ids:
    :return:
    """
    result = {}
    if not all([platform, service_ids]):
        return result
    service_ids = map(int, service_ids)

    from rpc.tool.protocol import gm_protocol
    sign_config = SignConfigV2.objects.first()
    stay_seconds = sign_config.browse_add_points if sign_config else 10
    service_task_status = get_service_browse_task_status(user_id=user_id, service_ids=service_ids)
    for _id in service_ids:
        has_task = 1 if service_task_status.get(str(_id)) else 0
        if platform.lower() == 'xcx':
            if has_task:
                url = XCX_URL_WITH_TASK.format(service_id=_id, stay_seconds=stay_seconds)
            else:
                url = XCX_URL_WITHOUT_TASK.format(service_id=_id)
            result.update({str(_id): url})
        else:
            url = gm_protocol.get_service_detail(
                id=_id, has_task=has_task, sign_task_seconds=stay_seconds, sign_points=20,
                transparent_key='rm_r63bkpbh_1',
            )
            result.update({str(_id): url})

    return {
        'url_info': result
    }
