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

from django.conf import settings
from django.db import transaction

from api.tool.user_tool import (
    filter_user_nick_name,
    get_portrait_by_user_id,
    get_user_from_context,
    get_user_by_id
)
from gm_types.gaia import VOTE_CHANGE_TYPE, VOTE_STATUS, IDOL_GENDER

from api.tool.variety_vote import get_current_activity_by_time, lock_user_invite_code
from api.models.variety_vote import VarietyActivity, VarietyIdol, UserInviteCode, \
    UserVote, InvoteStatistics, Invite
from api.models.user import User
from api.tasks.variety_vote import record_variety_vote, record_user_vote_num, record_invite, \
    record_invite_statistics
from api.tool.user_tool import is_new_user_local, get_auth_type_by_userid

from rpc.decorators import bind, bind_context
from rpc.tool.error_code import CODES, gen
from rpc.cache import variety_cache
from django.db.models import F, Sum


LOGIN_VOTE_NUM = 10
INVITE_VOTE_NUM = 10


@bind_context("api/variety_vote/code")
def get_user_invite_code(ctx, user_id=None):

    if not user_id:
        user = get_user_from_context(ctx)
    else:
        user = get_user_by_id(user_id)

    if not user:
        return None

    code = UserInviteCode.get_code(user)

    return code


@bind_context("api/variety_vote/user")
def variety_vote_user(ctx):
    """用户登录票调整。"""

    user = get_user_from_context(ctx)
    if not user:
        gen(CODES.LOGIN_REQUIRED)

    result = {
        "type": VOTE_STATUS.HAS_GET,  # gm-types
        "login_vote": 0,
        "change_vote": 0,
    }

    # redis查看是否已经获取票数
    today = date.today()
    key = "variety_vote_user-{user_id}-{date}".format(user_id=user.id, date=today)
    if variety_cache.get(key):
        return result

    activity, end = get_current_activity_by_time()
    user_vote = None
    if not end:

        now = datetime.now()
        ex = int(((now.replace(hour=0, second=0, minute=0, microsecond=0) + timedelta(days=1)) - now).total_seconds())
        variety_cache.set(key, 1, ex)

        user_vote, _ = UserVote.objects.get_or_create(user=user, activity=activity)
        user_vote.login_vote += LOGIN_VOTE_NUM
        user_vote.save()

        result["type"] = VOTE_STATUS.NOW_GET  # 领取登录票

    result["login_vote"] = user_vote.login_vote if user_vote else 0
    result["change_vote"] = LOGIN_VOTE_NUM if not end else 0

    # celery 记录UserVoteLog
    if not end:
        record_user_vote_num.delay(user_id=user.id, activity_id=activity.id,
                                  vote_num=LOGIN_VOTE_NUM, change_type=VOTE_CHANGE_TYPE.LOGIN)

    return result


@bind("api/variety_vote/index")
def variety_vote_index():
    """综艺投票首页信息获取"""

    result = {"end": False}

    # 活动相关
    activity, end = get_current_activity_by_time()
    result["end"] = end
    if activity:
        result.update(activity.data())

    return result


@bind_context("api/variety_vote/user_vote")
def variety_vote_user_vote(ctx):
    """获取用户剩余投票信息。"""

    result = {
        "is_login": False,
        "login_vote": 0,
        "invite_vote": 0,
    }

    user = get_user_from_context(ctx)
    if not user:
        return result

    result["is_login"] = True
    result["user_id"] = user.id
    try:
        activity, end = get_current_activity_by_time()
        user_vote = UserVote.objects.get(user=user, activity=activity)
        result.update(user_vote.data())
    except UserVote.DoesNotExist:
        pass
    except:
        pass

    return result


@bind("api/variety_vote/idol_list")
def idol_list(gender=IDOL_GENDER.MALE):

    activity, end = get_current_activity_by_time()
    if not activity:
        return []

    idols = VarietyIdol.objects.filter(activity_id=activity.id, is_online=True, gender=gender)
    result = [item.data() for item in idols]

    result.sort(key=lambda x:(x['vote_num'], -x['order']), reverse=True)
    if gender == IDOL_GENDER.FEMALE:
        for data in result[:3]:
            data['icon_url'] = data.pop('gif_url')
    return result


@bind_context("api/variety_vote/vote")
def vote(ctx, idol_id, activity_id, vote_num):
    """投票。"""

    user = get_user_from_context(ctx)
    if not user:
        gen(CODES.LOGIN_REQUIRED)

    activity = VarietyActivity.objects.get(pk=activity_id)
    if not activity.is_online:
        return gen(CODES.ACTIVITY_OFFLINE)

    now = datetime.now()
    if activity.start_time > now:
        return gen(CODES.ACTIVITY_NOT_START)

    if activity.end_time < now:
        return gen(CODES.ACTIVITY_END)

    try:
        user_vote = UserVote.objects.get(user=user, activity=activity)
    except:
        return gen(CODES.VOTE_NUM_NOT_ENOUGH)

    if not (user_vote.login_vote + user_vote.invite_vote) >= vote_num:  # 票数不足
        return gen(CODES.VOTE_NUM_NOT_ENOUGH)

    # 1、idol票数变化
    with transaction.atomic():
        idol = VarietyIdol.objects.select_for_update().get(pk=idol_id)
        idol.real_vote += vote_num
        idol.save()

    # 2、用户票数变化

    rest_login_vote = user_vote.login_vote - vote_num if user_vote.login_vote > vote_num else 0
    rest_invite_vote = user_vote.invite_vote - (0 if user_vote.login_vote > vote_num else vote_num - user_vote.login_vote)
    # user_vote = UserVote.objects.get(activity_id=activity_id, user_id=user.id)
    # user_vote.login_vote = vote_info.get("login_vote", 0)
    # user_vote.invite_vote = vote_info.get("invite_vote", 0)

    user_vote.login_vote = rest_login_vote
    user_vote.invite_vote = rest_invite_vote
    user_vote.save()

    # 3、投票记录表/用户票数变化记录表
    record_variety_vote.delay(idol_id, user.id, vote_num, activity_id)
    record_user_vote_num.delay(user_id=user.id, vote_num=vote_num, activity_id=activity.id,
                               change_type=VOTE_CHANGE_TYPE.VOTE)

    return {
        "login_vote": rest_login_vote,
        "invite_vote": rest_invite_vote,
    }


@bind_context("api/variety_vote/invite")
def invite(ctx, code, platform, device_id):
    """填写邀请码。"""

    user = get_user_from_context(ctx)
    if not user:
        gen(CODES.LOGIN_REQUIRED)

    # if user.userextra.risk_score > settings.VOTE_TONGDUN_RISK_SCORE:
    #     gen(CODES.TONGDUN_RISK)

    params = {
        'platform': platform,
        'device_id': device_id,
        'user': user if user else None,
        'old_user_reg_day': settings.NEW_USER_REG_MAX_DAY
    }
    is_new_user = is_new_user_local(**params)['is_new_user']
    if not is_new_user:
        gen(CODES.ACTIVITY_VOTE_OLD_USER)

    if Invite.objects.filter(device_id=device_id).exists():
        gen(CODES.ACTIVITY_VOTE_OLD_USER)

    try:
        user_invite_code = UserInviteCode.objects.get(code=code)
        if user_invite_code.user == user:
            gen(CODES.INVITE_CODE_IS_YOURS)
    except UserInviteCode.DoesNotExist:
        gen(CODES.INVITE_CODE_NOT_EXIST)

    activity, end = get_current_activity_by_time()
    if not end:

        if not activity or not activity.is_online:
            gen(CODES.ACTIVITY_OFFLINE)

        now = datetime.now()
        if activity.start_time > now:
            return gen(CODES.ACTIVITY_NOT_START)

        if activity.end_time < now:
            return gen(CODES.ACTIVITY_END)

        # 判断是否锁定用户，防止刷票
        lock_user_invite_code(user.id)

        if Invite.objects.filter(activity=activity, invitee=user):
            gen(CODES.HAS_INVITED)

        # 邀请人
        inviter, _ = UserVote.objects.get_or_create(user_id=user_invite_code.user_id, activity_id=activity.id)
        inviter.invite_vote += INVITE_VOTE_NUM
        inviter.save()

        # 被邀请人
        invitee, _ = UserVote.objects.get_or_create(user_id=user.id, activity_id=activity.id)
        invitee.invite_vote += INVITE_VOTE_NUM
        invitee.save()

        # 记录用户邀请记录
        record_invite.delay(inviter_id=user_invite_code.user_id,
                            invitee_id=user.id, activity_id=activity.id,
                            device_id=device_id, platform=platform)
        record_invite_statistics.delay(inviter_id=user_invite_code.user_id,
                                       activity_id=activity.id,
                                       date=date.today())
        record_user_vote_num.delay(user_id=user.id, activity_id=activity.id,
                                   vote_num=INVITE_VOTE_NUM, change_type=VOTE_CHANGE_TYPE.INVITE)
        record_user_vote_num.delay(user_id=user_invite_code.user_id, activity_id=activity.id,
                                   vote_num=INVITE_VOTE_NUM, change_type=VOTE_CHANGE_TYPE.INVITE)

    else:
        if not activity:
            return gen(CODES.ACTIVITY_END)

        now = datetime.now()
        if activity.start_time > now:
            return gen(CODES.ACTIVITY_NOT_START)

        if activity.end_time < now:
            return gen(CODES.ACTIVITY_END)

    return {
        "login_vote": invitee.login_vote,
        "invite_vote": invitee.invite_vote,
    }


@bind('api/variety_vote/share')
def variety_vote_share(inviter_id=None, idol_id=None, activity_id=None):
    """分享页面idol的信息"""

    data = {}
    idol_list = VarietyIdol.objects.filter(activity_id=activity_id, is_online=True)
    data['idol_list'] = [idol.data() for idol in idol_list]
    try:
        inviter = UserInviteCode.objects.get(user__id=inviter_id)
        inviter_nick_name = filter_user_nick_name(user=inviter.user) if inviter else None
        data['inviter'] = {
            'id': inviter_id,
            'nick_name': inviter_nick_name,
            'invite_code': inviter.code
        }
    except UserInviteCode.DoesNotExist:
        data['inviter'] = {}

    try:
        share_idol = VarietyIdol.objects.get(activity_id=activity_id, id=idol_id, is_online=True) if idol_id else None
    except VarietyIdol.DoesNotExist:
        share_idol = None
        data['share_idol'] = {}

    if share_idol:
        data['share_idol'] = {
            'id': share_idol.id,
            'nick_name': share_idol.nick_name,
            'vote_num': share_idol.hera_vote_num + share_idol.real_vote,
        }

    return data


@bind_context('api/variety_vote/data_inviter')
def data_inviter(ctx, activity_id=None, count=50, offset=0):

    user = get_user_from_context(ctx)

    data, inviters = {}, []

    inviter_list = InvoteStatistics.objects.filter(activity_id=activity_id).\
        values("inviter", "activity").annotate(total_cnt=Sum('hera_invite_cnt')+Sum('real_invite_cnt')).order_by(
        Sum('hera_invite_cnt') + Sum('real_invite_cnt')
    ).all().reverse()[offset:count]

    user_ids = list(map(lambda i: i["inviter"], inviter_list))
    users = User.objects.filter(pk__in=user_ids) if user_ids else []
    users_info = {user.id: filter_user_nick_name(user) for user in users}

    data['inviters'] = []
    for inviter in inviter_list:
        er = inviter["inviter"]
        data['inviters'].append({
            'user_id': er,
            'user_type': get_auth_type_by_userid(er),
            'nick_name': users_info.get(er, ""),
            'portrait': get_portrait_by_user_id(er),
            'invitations':  inviter["total_cnt"],
        })

    try:
        activity = VarietyActivity.objects.get(id=activity_id)
        data.update(activity.data())
    except VarietyIdol.DoesNotExist:
        pass

    user_inviter = InvoteStatistics.objects.filter(activity_id=activity_id, inviter__id=user.id). \
        values("inviter", "activity").annotate(total_cnt=Sum('hera_invite_cnt')+Sum('real_invite_cnt')) if user else None

    data['my'] = {}
    if user:
        data['my'] = {
            "user_id": user.id,
            'user_type': get_auth_type_by_userid(user.id),
            'nick_name': filter_user_nick_name(user=user),
            'portrait': get_portrait_by_user_id(user.id),
            'invitations': 0,
        }
    if user_inviter:
        data['my'].update({
            'portrait': get_portrait_by_user_id(user.id),
            'invitations': user_inviter[0]["total_cnt"]
        })

    return data


@bind('api/variety_vote/base_inviter')
def base_inviter(activity_id=None):

    activity = VarietyActivity.objects.get(id=activity_id)

    return {
        'id': activity_id,
        'name': activity.name,
        'title': activity.title,
        'header_banner': activity.header_banner,
    }
