# -*- coding:utf-8 -*-
'''
date: 2019-04-03
助力拿好礼表定义
'''

import datetime
import traceback

from gm_types.error import ERROR as ERROR_CODES
from gm_types.gaia import TEMP_ACTIVITY_TYPE

from django.db import models, transaction
from django.db.models import Sum
from django.contrib.auth.models import User

from rpc.tool.random_tool import random_str
from rpc.tool.log_tool import user_activity_logger
from api.models import base_model
from gm_upload import ImgUrlField, IMG_TYPE


class AssistPrize(base_model.BaseModel):
    '''
    助力活动定义
    '''

    class Meta:
        verbose_name = '助力活动奖品'
        app_label = 'api'
        db_table = 'api_assist_prize'

    name = models.CharField(max_length=255, verbose_name='奖品名称', null=False)
    stock = models.IntegerField(verbose_name='商品库存数量', null=False, default=0)
    consume_count = models.IntegerField(verbose_name='消费数量', null=False, default=0)
    pb_color_pre = models.CharField(max_length=255, verbose_name='进度条前置色', null=False)
    pb_color_bg = models.CharField(max_length=255, verbose_name='进度条背景色', null=False)
    font_color = models.CharField(max_length=255, verbose_name='字体颜色', null=False)
    start_time = models.DateTimeField(verbose_name='活动开始时间')
    end_time = models.DateTimeField(verbose_name='活动结束时间')
    assist_time_long = models.IntegerField(verbose_name='助力时长(h)', null=True)
    assist_num = models.IntegerField(verbose_name='助力人数', null=False)
    bg_img_url = ImgUrlField(verbose_name='背景图', max_length=255, img_type=IMG_TYPE.NOWATERMARK)
    share_button_img_url = ImgUrlField(verbose_name='分享按钮图', max_length=255, img_type=IMG_TYPE.NOWATERMARK)
    invite_frame_img_url = ImgUrlField(verbose_name='邀请框图片', max_length=255, img_type=IMG_TYPE.NOWATERMARK)
    assist_frame_img_url = ImgUrlField(verbose_name='助力详情框图片', max_length=255, img_type=IMG_TYPE.NOWATERMARK)
    share_bg_img_url = ImgUrlField(verbose_name='分享背景图', max_length=255, img_type=IMG_TYPE.NOWATERMARK)
    description = models.TextField(verbose_name='活动规则', max_length=20000, null=True, blank=True)
    jump_type = models.CharField(max_length=40, verbose_name='跳转类型', null=True)
    jump_id = models.IntegerField(verbose_name='跳转详情', null=True)
    jump_url = models.CharField(max_length=255, verbose_name='跳转链接', null=True)


    def detail_info(self):
        result = {}
        fields = self._meta.fields
        pop_fields = ['is_online', 'is_deleted', 'create_time', 'update_time']
        for f in fields:
            f_name = f.name
            if f_name not in pop_fields:
                result[f_name] = getattr(self, f_name)
        result['valid_stock'] = result['stock'] - result['consume_count']
        return result

    @classmethod
    def detail_info_by_id(cls, p_id):
        '''
        获取detail详情
        '''
        try:
            obj = cls.objects.get(id=p_id, is_online=True)
            return obj.detail_info()
        except:
            return {}


CAN_NOT_RECEIVE = 0
CAN_RECEIVE = 1
RECEIVED = 2

class AssistCode(base_model.BaseModel):
    '''
    助力码
    '''
    class Meta:
        verbose_name = '助力码'
        app_label = 'api'
        db_table = 'api_assist_code'

    user = models.ForeignKey(User)
    start_time = models.DateTimeField(verbose_name='开始时间')
    end_time = models.DateTimeField(verbose_name='失效时间')
    a_code = models.CharField(max_length=60, verbose_name='助力码', null=False, default='', unique=True)
    assistprize = models.ForeignKey(AssistPrize)
    suc_count = models.IntegerField(verbose_name='成功个数', null=False, default=0)
    receive_status = models.IntegerField(verbose_name='领取状态', null=False, default=CAN_NOT_RECEIVE)


    @classmethod
    def update_receive_status(cls, user_id, a_code, r_status=CAN_RECEIVE):
        cls.objects.filter(user_id=user_id, a_code=a_code).update(receive_status=r_status)

    @classmethod
    def increase_suc_count(cls, a_code):
        '''
        每助力成功一个, 记录成功个数
        '''
        with transaction.atomic():
            obj = cls.objects.select_for_update().select_related('assistprize').get(a_code=a_code)
            obj.suc_count += 1
            obj.save()
            if obj.suc_count == obj.assistprize.assist_num:
                obj.assistprize.consume_count += 1
                obj.assistprize.save()

    @property
    def assist_success(self):
        '''
        判断该次code是否邀请成功
        '''
        return self.suc_count >= self.assistprize.assist_num

    @classmethod
    def get_successful_user_by_pid(cls, pid):
        '''
        获取满足领取条件的用户
        '''
        assist_num = AssistPrize.detail_info_by_id(pid)['assist_num']
        user_id_list = list(cls.objects.filter(suc_count__gte=assist_num, assistprize_id=pid).values_list('user_id', flat=True).order_by('-update_time'))
        return user_id_list

    @classmethod
    def get_obj_by_acode(cls, acode):
        '''
        根据助力码获取记录
        '''
        try:
            return cls.objects.get(a_code=acode)
        except:
            return None

    @classmethod
    def get_last_record_by_uid_pid(cls, user_id, pid):
        try:
            obj = cls.objects.filter(user_id=user_id, assistprize_id=pid).order_by('-start_time').first()
            if obj:
                return obj
            else:
                _res, obj = cls.get_new_acode_for_pid(user_id, pid)
                if _res:
                    return obj
                return None
        except:
            print(traceback.format_exc())
            return None


    def detail_info(self):
        output_list = ['start_time', 'end_time', 'a_code', 'user_id', 'assistprize_id', 'receive_status']
        result = {}
        for okey in output_list:
            result[okey] = getattr(self, okey)
        result['has_collected_address'] = result['receive_status'] >= CAN_RECEIVE
        return result

    @classmethod
    def gen_assist_code(cls, uid, pid):
        '''
        生成助力码
        '''
        while True:
            acode = '_'.join([str(pid), str(uid), random_str(16)])
            if not cls.objects.filter(a_code=acode).exists():
                break
        return acode

    @classmethod
    def get_new_acode_for_pid(cls, uid, pid):
        '''
        获取用户对应商品当前有效的助力码, 没有则创建
        '''
        now = datetime.datetime.now()
        obj = None
        try:
            obj = cls.objects.get(end_time__gt=now, user_id=uid, assistprize_id=pid)
            return True, obj
        except:
            pass

        prize_info = AssistPrize.detail_info_by_id(pid)
        if not prize_info:
            return False, ERROR_CODES.ASSIST_PRIZE_INVALID
        if prize_info['end_time'] <= now:
            return False, ERROR_CODES.ASSIST_PRICE_EXPIRED

        time_long = prize_info['assist_time_long']
        end_time = prize_info['end_time']
        if time_long:
            end_time = min(now + datetime.timedelta(hours=time_long), end_time)

        new_obj = cls()
        new_obj.user_id = uid
        new_obj.a_code = cls.gen_assist_code(uid, pid)
        new_obj.assistprize_id = pid
        new_obj.start_time = now
        new_obj.end_time = end_time
        new_obj.save()
        return True, new_obj


class AssistThirdInfo(base_model.BaseModel):
    '''
    记录第三方信息
    '''
    class Meta:
        verbose_name = '助力者第三方信息'
        app_label = 'api'
        db_table = 'api_assist_thirdinfo'

    platform_id = models.CharField(verbose_name='第三方平台id', max_length=255, null=False)
    nickname = models.CharField(verbose_name='昵称', max_length=255, null=False)
    img_url = models.CharField(verbose_name='头像', max_length=255, null=False)

    def get_detail_info(self):
        result = {}
        result['nickname'] = self.nickname
        result['img_url'] = self.img_url
        return result

    @classmethod
    def upsert(cls, platform_id, nickname, img_url):
        '''
        get_or_create 记录信息, 如果有则更新
        '''
        obj, _created = cls.objects.get_or_create(platform_id=platform_id, defaults={'nickname':nickname, 'img_url':img_url})
        if not _created:
            obj.nickname = nickname
            obj.img_url = img_url
            obj.save()
        return obj

    @classmethod
    def get_record_by_platform_id(cls, platform_id):
        '''
        根据平台id获取记录
        '''
        try:
            return cls.objects.get(platform_id=platform_id)
        except:
            return None


class ActUserWechatInfo(base_model.BaseModel):
    '''
    记录活动中 更美用户微信信息的绑定关系
    '''
    class Meta:
        verbose_name = '用户微信关联表'
        app_label = 'api'
        db_table = 'api_activity_user_wechat'

    user = models.ForeignKey(User)
    third_info = models.ForeignKey(AssistThirdInfo)
    activity_type = models.IntegerField(verbose_name='活动类型', choices=TEMP_ACTIVITY_TYPE, default=TEMP_ACTIVITY_TYPE.NORMAL_ASSIST)

    @classmethod
    def get_third_detail_by_uid_aty(cls, user_id, aty_type):
        '''
        根据用户id, 获取第三方详情
        '''
        if not user_id:
            return {}

        try:
            obj = cls.objects.get(user_id=user_id, activity_type=aty_type)
            return obj.third_info.get_detail_info()
        except:
            user_activity_logger.error(traceback.format_exc())
            return {}

    @classmethod
    def create_bind_relation(cls, user_id, open_id, aty_type=TEMP_ACTIVITY_TYPE.NORMAL_ASSIST):
        '''
        根据用户id, open_id创建关联记录
        '''
        try:
            third_obj = AssistThirdInfo.get_record_by_platform_id(open_id)
            if not third_obj:
                user_activity_logger.info('[activity] get no thirdinfo by open_id(%s)' % (open_id))
                return False

            obj, _created = cls.objects.get_or_create(user_id=user_id, activity_type=aty_type, defaults={'third_info':third_obj})
            if not _created:
                if str(obj.third_info_id) != str(third_obj.id):
                    obj.third_info = third_obj
                    obj.save()
            return True
        except:
            user_activity_logger.error(traceback.format_exc())
            return False


class Assister(base_model.BaseModel):
    '''
    助力记录
    '''
    class Meta:
        verbose_name = '助力者'
        app_label = 'api'
        db_table = 'api_assister'

    user = models.ForeignKey(User)
    a_code = models.ForeignKey(AssistCode, to_field="a_code", db_column='a_code')
    # a_code = models.CharField(max_length=60, verbose_name='助力码', null=False, default='')
    assist_status = models.IntegerField(verbose_name='助力状态', null=False, default=1)


    def get_third_info(self):
        return ActUserWechatInfo.get_third_detail_by_uid_aty(user_id=self.user_id, aty_type=TEMP_ACTIVITY_TYPE.NORMAL_ASSIST)

    @classmethod
    def get_assister_by_code(cls, a_code):
        '''
        根据助力码获取助力者信息
        '''

        a_list = cls.objects.filter(a_code=a_code).order_by('-create_time').all()
        result = []
        for aa in a_list:
            ainfo = {}
            ainfo['create_time'] = aa.create_time
            ainfo['assist_status'] = aa.assist_status
            ainfo.update(aa.get_third_info())
            result.append(ainfo)
        return result


    @classmethod
    def has_assisted_by_uid_code(cls, user_id, a_code):
        '''
        判断用户是否参与了此次助力
        '''
        if not all([user_id, a_code]):
            return False
        return cls.objects.filter(user_id=user_id, a_code=a_code, assist_status=1).exists()


    @classmethod
    def create_record(cls, user_id, a_code, assist_status):
        '''
        创建邀请者记录
        '''
        try:
            obj, _created = cls.objects.get_or_create(user_id=user_id, defaults={'a_code_id':a_code, 'assist_status': assist_status})
            if obj.assist_status:
                if _created:
                    AssistCode.increase_suc_count(a_code)
                return True
            return False
        except:
            user_activity_logger.error(traceback.format_exc())
            return False
