# coding=utf-8
from datetime import datetime, timedelta
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Sum

from statistic.models import Device
from gm_types.gaia import RED_PACKET, TRANS_ACTION, TRANS_EVENT, TRANS_STATUS, REJECT_REASON


# Create your models here.
class Dialog(models.Model):

    type = models.SmallIntegerField(choices=RED_PACKET, unique=True)
    packet_id = models.IntegerField(verbose_name="关联红包ID")

    @property
    def packet(self):
        """
        Get current packet data.
        :return:
        """
        p = RedPacket.objects.filter(packet_type=self.type, is_online=True).latest('create_time')
        if self.packet_id != p.id:
            self.packet_id = p.id
            self.save()
        return p

    @classmethod
    def initialize(cls):
        """

        :return:
        """
        if len(Dialog.objects.all()) < 2:
            try:
                Dialog.objects.create(
                    type=RED_PACKET.INVITE,
                    packet_id=RedPacket.objects.filter(
                        packet_type=RED_PACKET.INVITE,
                        is_online=True
                    ).latest('create_time').id
                )
            except:
                pass

            try:
                Dialog.objects.create(
                    type=RED_PACKET.CASH,
                    packet_id=RedPacket.objects.filter(
                        packet_type=RED_PACKET.CASH,
                        is_online=True
                    ).latest('create_time').id
                )
            except:
                pass


class DialogAction(models.Model):
    """
    先从用户维度判断，
    再从设备维度判断。
    """
    CANCELED = 0
    OPENED = 1

    ACTION = (
        (OPENED, "打开弹窗"), (CANCELED, "关闭弹窗")
    )

    dialog = models.ForeignKey(Dialog, verbose_name="关联弹窗")
    user = models.ForeignKey(User, blank=True, null=True, verbose_name="关联用户")
    action = models.SmallIntegerField(choices=ACTION)
    device_id = models.CharField(max_length=64, verbose_name="设备ID")

    create_at = models.DateTimeField(auto_now_add=True)


class TransactionRemark(models.Model):
    """
    流水记录备注：
    现金红包ID，邀请成功ID，兑换码
    """

    event_type = models.SmallIntegerField(choices=TRANS_EVENT)
    packet_id = models.IntegerField(null=True, blank=True)
    registration_id = models.IntegerField(null=True, blank=True)
    cdkey = models.CharField(max_length=32, blank=True, null=True, verbose_name=u"兑换码")


class TransactionLog(models.Model):
    """
    流水记录
    """

    user = models.ForeignKey(User, db_index=True)
    amount = models.FloatField(verbose_name=u"交易金额")
    type = models.SmallIntegerField(choices=TRANS_ACTION, verbose_name=u"交易类型", db_index=True)
    state = models.SmallIntegerField(choices=TRANS_STATUS, default=TRANS_STATUS.WAIT, verbose_name=u"交易状态")
    remark = models.OneToOneField(TransactionRemark, blank=True, null=True, verbose_name=u"交易备注")

    create_at = models.DateTimeField(auto_now_add=True)
    update_at = models.DateTimeField(auto_now=True)

    @property
    def data(self):
        """

        :return:
        """
        invitee_phone = ""
        if self.remark.registration_id:
            invitee = Registration.objects.get(pk=self.remark.registration_id).invitee
            invitee_phone = invitee.person.phone[:3] + "****" + invitee.person.phone[8:]

        return {
            "type": self.remark.event_type,
            "amount": self.amount,
            "state": self.state,
            "cdkey": self.remark.cdkey,
            "invitee_phone": invitee_phone,
            "time": self.update_at.strftime("%m-%d %H:%M")
        }


class Registration(models.Model):
    """
    邀请注册记录：
    首次登录时间，注册/登录上下文
    """
    inviter = models.ForeignKey(User, related_name="inviter", verbose_name=u"邀请者")
    invitee = models.ForeignKey(User, related_name="invitee", verbose_name=u"被邀请者")

    device_id = models.CharField(max_length=64, blank=True, null=True)
    device_type = models.CharField(max_length=32, blank=True, null=True)

    activated = models.BooleanField(default=False, verbose_name=u"已激活")
    register_time = models.DateTimeField(null=True, blank=True)
    login_time = models.DateTimeField(null=True, blank=True)

    class Meta:
        unique_together = (
            ('inviter', 'invitee')
        )

    @classmethod
    def cheatingProd(cls, user):
        """
        作弊概率
        :param user:
        :return:
        """
        return 0.0


class RedPacket(models.Model):
    """
    红包配置
    """

    packet_type = models.CharField(u'红包类型', choices=RED_PACKET, default=RED_PACKET.INVITE, max_length=2)
    amount = models.FloatField(u'红包金额', default=0)
    create_time = models.DateTimeField(u'创建时间', auto_now_add=True)
    is_online = models.BooleanField(u'是否上线', default=False)

    @property
    def data(self):
        return {
            "id": self.id, "amount": self.amount,
        }


class UserBalance(models.Model):
    """
    用户余额
    """
    user = models.OneToOneField(User, verbose_name=u'用户', unique=True)
    join_time = models.DateTimeField(u'加入时间', auto_now_add=True)


class CashBackAuditLog(models.Model):
    """
    提现审核记录
    """

    transactionlog = models.ForeignKey(TransactionLog, verbose_name=u'关联流水记录')
    user = models.ForeignKey(User, verbose_name=u'审核人员')
    status = models.CharField(u'审核状态', max_length=2, choices=TRANS_STATUS,
                              default=TRANS_STATUS.WAIT)
    time = models.DateTimeField(u'审核时间', auto_now_add=True)
    reason = models.CharField(u'驳回原因', max_length=2, choices=REJECT_REASON, null=True)


class CashbackManager(object):

    @classmethod
    def getInviterList(cls):
        return Registration.objects.values_list("inviter", flat=True).distinct()

    @classmethod
    def getUserIncome(cls, user):
        tl = TransactionLog.objects.filter(user=user, type=TRANS_ACTION.DEPOSIT).aggregate(Sum("amount"))
        return round(tl['amount__sum'] or 0, 2)

    @classmethod
    def getUserBalance(cls, user):
        tl = TransactionLog.objects.filter(user=user, state__in=[TRANS_STATUS.PASS, TRANS_STATUS.WAIT]).aggregate(Sum("amount"))
        return round(tl['amount__sum'] or 0, 2)

    @classmethod
    def getUserInviteNum(cls, user):
        return Registration.objects.filter(inviter=user).count()

    @classmethod
    def getUserWithdraw(cls, user):
        tl = TransactionLog.objects.filter(user=user,
                                           type=TRANS_ACTION.WITHDRAW,
                                           state=TRANS_STATUS.PASS).aggregate(Sum("amount"))
        return abs(round(tl['amount__sum'] or 0, 2))

    @classmethod
    def listSuspect(cls):
        for inviter_id in Registration.objects.values_list('inviter', flat=True).distinct():
            u = User.objects.get(pk=inviter_id)
            print("[{}]: {}".format(u.id, cls.isSuspect(u)))

    @classmethod
    def isSuspect(cls, user):
        """

        :param user:
        :return:
        """
        # http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=5482753
        # 若该用户邀请成功的人数注册时间差在10分钟之内的超过5人，即判断该用户为嫌疑用户
        queryset = Registration.objects.filter(inviter=user, activated=True).order_by("register_time").values_list("register_time", flat=True)
        n = len(queryset)
        if n >= 5:
            for i, t in enumerate(queryset):
                if n > i + 4 and queryset[i + 4] - queryset[i] <= timedelta(minutes=10):
                    return True

        # 若该用户邀请成功的人数中“设备登录其他id”字段中“是”的比例超过30%，即判断该用户为有嫌疑用户
        queryset = Device.objects.raw("""
            SELECT sdu.id, sdu.user_id, COUNT(distinct sdu2.`user_id`) as users
            FROM `statistic_device_user` sdu
            LEFT JOIN `statistic_device_user` sdu2 ON sdu2.device_id = sdu.device_id AND sdu2.`user_id` IN (
                SELECT id FROM `auth_user` WHERE date_joined > DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
            )
            WHERE sdu.`user_id` IN (
                  SELECT `invitee_id` FROM `cashback_registration` WHERE `inviter_id` = {inviter_id} AND `activated` = 1
            )
            GROUP BY sdu.user_id;
        """.format(inviter_id=user.id))

        if len(filter(lambda d: d.users > 1, queryset)) > len(filter(lambda d: True, queryset)) * 0.3:
            return True

        return False

    @classmethod
    def isLoginOthers(cls, device_id):
        return device_id and Device.objects.filter(device_id=device_id).values_list("user", flat=True).count() > 1

    @classmethod
    def getRedPacketCount(cls, redpacket_id):
        return TransactionLog.objects.filter(remark__packet_id=redpacket_id, state=TRANS_STATUS.PASS).count()

    @classmethod
    def getUserAudit(cls, user):
        tl = TransactionLog.objects.filter(user=user,
                                           type=TRANS_ACTION.WITHDRAW,
                                           state=TRANS_STATUS.WAIT).aggregate(Sum("amount"))
        return abs(tl['amount__sum']) if tl['amount__sum'] else 0.0
