# coding=utf-8

import json
import datetime

from django.utils import timezone
from django.db.models import Q

from apps.rebate.models import CashRebate, PointRebate, CashRebateLog, PointRebateLog, PointGive, PointGiveLog, TransferCashRebate, TransferCashRebateDetail, CashTransferLog
from apps.customer.models import SuperiorDistributor
from apps.order.models import Order
from apps.config.models import Config
from apps.WechatApplet.models import WechatApplet
from apps.customer.models import CustomerWechat

from utils.wechatpayv3.transfer import Transfer
from utils.exceptions import CustomError


class CustomerRebate(object):

    def __init__(self, pay):
        self.pay = pay
        self.order = Order.objects.filter(pay=self.pay).first()

    def cash_rebate(self, ratio, amount, customer):
        '''
        计算现金返利  1、2、3级分销商 返现金
        :param ratio:
        :param amount:
        :param customer:
        :return:
        '''
        rebate = CashRebate.objects.create(
            order=self.order,
            ratio=ratio,
            amount=amount,
            customer=customer,
            create_time=timezone.now()
        )
        CashRebateLog.addnew(rebate)

    def point_rebate(self, ratio, amount, customer):
        '''
        计算积分返利  4、5级分销商 返积分
        :param ratio:
        :param amount:
        :param customer:
        :return:
        '''
        rebate = PointRebate.objects.create(
            order=self.order,
            ratio=ratio,
            amount=amount,
            customer=customer,
            create_time=timezone.now()
        )
        PointRebateLog.addnew(rebate)

    def point_give(self, ratio, amount, customer):
        '''
        计算购买商品赠送的积分  购买商品时根据后台设置的比例赠送相应的积分给购买者
        :param ratio:
        :param amount:
        :param customer:
        :return:
        '''
        give = PointGive.objects.create(
            order=self.order,
            ratio=ratio,
            amount=amount,
            customer=customer,
            create_time=timezone.now()
        )
        PointGiveLog.addnew(give)

    def calcul_rebate(self):
        '''
        计算返利并保存log
        :return:
        '''
        if not self.order:
            return
        if self.order.total_amount <= 0:
            return
        if self.order.status == Order.WAIT_PAY or self.order.status == Order.CANCEL:
            return

        customer = self.order.customer
        sd = SuperiorDistributor.objects.filter(customer=customer).first()
        if not sd:
            return
        # 判断是首次购买还是再次购买  首次购买与再次购买返利的比例不同
        count = Order.objects.filter(customer=customer, status__in=[Order.WAIT_DISPATCH, Order.CONFIRM_DISPATCH]).count()
        rebate_dic = {}
        if count > 1:
            rebate_dic = Config.get_rebate(False)
        elif count == 1:
            rebate_dic = Config.get_rebate(True)
        # 现金保留两位小数， 积分整数
        total_amount = float(self.order.total_amount or 0)

        if sd.one_level and sd.one_level.is_distributor and rebate_dic['one_level'] > 0:
            amount = int(round(total_amount * rebate_dic['one_level'] / 100.0, 0))
            self.cash_rebate(rebate_dic['one_level'], amount, sd.one_level)

        if sd.two_level and sd.two_level.is_distributor and rebate_dic['two_level'] > 0:
            amount = int(round(total_amount * rebate_dic['two_level']/ 100.0, 0))
            self.cash_rebate(rebate_dic['two_level'], amount, sd.two_level)

        if sd.three_level and sd.three_level.is_distributor and rebate_dic['three_level'] > 0:
            amount = int(round(total_amount * rebate_dic['three_level'] / 100.0, 0))
            self.cash_rebate(rebate_dic['three_level'], amount, sd.three_level)

        if sd.four_level and sd.four_level.is_distributor and rebate_dic['four_level'] > 0:
            amount = int(round((total_amount / 100.0) * (rebate_dic['four_level'] / 100.0), 0))
            self.point_rebate(rebate_dic['four_level'], amount, sd.four_level)

        if sd.five_level and sd.five_level.is_distributor and rebate_dic['five_level'] > 0:
            amount = int(round((total_amount / 100.0) * (rebate_dic['five_level'] / 100.0), 0))
            self.point_rebate(rebate_dic['five_level'], amount, sd.five_level)

        # 计算购买商品 赠送积分
        rule = Config.get_value(Config.KEY_POINT_RULE)
        if rule > 0:
            amount = int(round((total_amount / 100.0) * (rule / 100.0), 0))
            self.point_give(rule, amount, customer)


class CustomerRebateTransfer(object):

    def __init__(self, order):
        wx = WechatApplet.objects.filter().first()
        if not wx:
            raise Exception(u'小程序appid认证失败！')
        self.order = order
        self.wx = wx

    def apply_transfer_again(self, instance):
        '''转账批次明细失败 重新申请新的批次进行转账  要判断该明细有没有已经申请重新转账 和  判断用户余额'''
        count = TransferCashRebateDetail.objects.filter(Q(rebate=instance.rebate), ~Q(status=TransferCashRebateDetail.FAIL)).count()
        if count:
            raise CustomError(u'该转账明细，正在支付，禁止重复申请！')
        if instance.customer.balance < instance.amount:
            raise CustomError(u'申请转账金额超出客户[{}]余额，禁止申请！'.format(instance.customer.name))

        if instance.amount > self.order.total_amount:
            raise CustomError(u'转账总金额大于收款总金额！')
        if instance.amount == 0:
            raise CustomError(u'转账总金额为0！')

        tc = TransferCashRebate.objects.create(order=instance.main.order, transfer_num=1, transfer_amount=instance.amount)
        tc_no = 'TC{}{:0>4}'.format(timezone.now().strftime('%Y%m%d%H%M%S'), tc.id)
        tc.no = tc_no
        tc.save()
        tcd = TransferCashRebateDetail.objects.create(main=tc, rebate=instance.rebate, amount=instance.amount, customer=instance.customer)
        tcd_no = 'TCD{}{:0>4}'.format(timezone.now().strftime('%Y%m%d%H%M%S'), tcd.id)
        tcd.no = tcd_no
        tcd.save()
        return tc

    def create_transfer(self):
        '''
        转账的时候创建转账批次单 和转账批次单明细
        如果是没有转账批次的 添加新的转账批次和转账批次明细  如果有转账批次的 只创建失败的
        要判断收款人的余额
        如果订单已经申请过转账批次 就不能再申请了 只能在付款失败的批次明细里边重新申请（没有考虑订单关闭的请框）
        :return:
        '''
        count = TransferCashRebate.objects.filter(order=self.order).count()
        if count:
            raise CustomError(u'该返利已申请转账，禁止重复申请！')
        tc = TransferCashRebate.objects.create(order=self.order)
        tc_no = 'TC{}{:0>4}'.format(timezone.now().strftime('%Y%m%d%H%M%S'), tc.id)
        rows = CashRebate.objects.filter(order=self.order)
        transfer_amount = 0
        transfer_num = 0
        for row in rows:
            if row.customer.balance < row.amount:
                raise CustomError(u'客户[{}]余额不足！'.format(row.customer.name))
            transfer_num += 1
            transfer_amount += row.amount
            tcd = TransferCashRebateDetail.objects.create(main=tc, rebate=row, amount=row.amount, customer=row.customer)
            tcd_no = 'TCD{}{:0>4}'.format(timezone.now().strftime('%Y%m%d%H%M%S'), tcd.id)
            tcd.no = tcd_no
            tcd.save()
        if transfer_amount > self.order.total_amount:
            raise CustomError(u'转账总金额大于收款总金额！')
        if transfer_num == 0:
            raise CustomError(u'转账总笔数为0！')
        if transfer_amount == 0:
            raise CustomError(u'转账总金额为0！')
        tc.no = tc_no
        tc.transfer_num = transfer_num
        tc.transfer_amount = transfer_amount
        tc.save()
        return tc

    def transfer_rebate(self, detail=None):
        '''
        现金返利转账申请
        :return:
        '''
        if detail:
            tc = self.apply_transfer_again(detail)
        else:
            tc = self.create_transfer()

        transfer_detail_list = []
        rows = TransferCashRebateDetail.objects.filter(main=tc)
        for row in rows:
            wx_c = CustomerWechat.objects.filter(wechat_app=self.wx, customer=row.customer).first()
            if not wx_c:
                continue
            item = {
                'out_detail_no': row.no,
                'transfer_amount': row.amount,
                'transfer_remark': '订单{}返利'.format(self.order.no),
                'openid': wx_c.openid
            }
            # 注意 明细转账金额 大于等于  2000  收款用户姓名必须
            transfer_detail_list.append(item)

        appid = self.wx.authorizer_appid
        out_batch_no = self.order.no
        batch_name = '订单{}返利'.format(self.order.no)
        batch_remark = '订单{}返利'.format(self.order.no)
        total_amount = tc.transfer_amount
        total_num = tc.transfer_num

        t = Transfer(self.wx)
        code, message = t.transfer_batch(appid, out_batch_no, batch_name, batch_remark, total_amount, total_num, transfer_detail_list)
        result = json.loads(message)
        if code != 200:
            raise Exception(u'[{}]转账申请失败！原因：{}'.format(self.order.no, result))

        batch_id = result.get('batch_id')
        create_time = result.get('create_time')
        tc.transfer_status = TransferCashRebate.ACCEPTED
        if batch_id:
            tc.batch_id = batch_id
        if create_time:
            tc.transfer_time = datetime.datetime.strptime(create_time, "%Y-%m-%dT%H:%M:%S+08:00")
        tc.save()
        TransferCashRebateDetail.objects.filter(main=tc).update(status=TransferCashRebateDetail.PENDING)


def transfer_refresh(transfer):
    # 如果转账批次单 已经受理30天了 中间没有刷新  状态是已受理  然后受理时间到当前时间超过30
    wx = WechatApplet.objects.filter().first()
    if not wx:
        raise Exception(u'小程序appid认证失败！')
    t = Transfer(wx)
    code, message = t.transfer_query_out_batch_no(transfer.no, need_query_detail=False, offset=0, limit=20, detail_status='ALL')
    result = json.loads(message)
    if code != 200:
        # 如果查询结果  NOT_FOUND   记录不存在 且转账批次单的状态是已申请  把状态改成  未处理  重新申请
        raise Exception(u'转账[{}]查询失败！原因：{}'.format(transfer.no, result))

    transfer_batch = result.get('transfer_batch')
    if not transfer_batch:
        return
    batch_id = transfer_batch.get('batch_id')
    batch_status = transfer_batch.get('batch_status')
    close_reason = transfer_batch.get('close_reason')
    create_time = transfer_batch.get('create_time')
    update_time = transfer_batch.get('update_time')
    success_amount = transfer_batch.get('success_amount')
    success_num = transfer_batch.get('success_num')
    fail_amount = transfer_batch.get('fail_amount')
    fail_num = transfer_batch.get('fail_num')

    if batch_id and not transfer.batch_id:
        transfer.batch_id = batch_id
    if batch_status:
        if batch_status == 'WAIT_PAY':
            transfer.transfer_status = TransferCashRebate.WAIT_PAY
        elif batch_status == 'ACCEPTED':
            transfer.transfer_status = TransferCashRebate.ACCEPTED
        elif batch_status == 'PROCESSING':
            transfer.transfer_status = TransferCashRebate.PROCESSING
        elif batch_status == 'FINISHED':
            transfer.transfer_status = TransferCashRebate.FINISHED
        elif batch_status == 'CLOSED':
            transfer.transfer_status = TransferCashRebate.CLOSED
    if close_reason:
        transfer.close_reason = close_reason
    if create_time and not transfer.transfer_time:
        transfer.transfer_time = datetime.datetime.strptime(create_time, "%Y-%m-%dT%H:%M:%S+08:00")
    if update_time:
        transfer.update_time = datetime.datetime.strptime(update_time, "%Y-%m-%dT%H:%M:%S+08:00")
    if success_amount:
        transfer.success_amount = success_amount
    if success_num:
        transfer.success_num = success_num
    if fail_amount:
        transfer.fail_amount = fail_amount
    if fail_num:
        transfer.fail_num = fail_num
    transfer.save()
    # 转账结束的时候  自动更新明细信息
    if batch_status and batch_status == 'FINISHED':
        detail = TransferCashRebateDetail.objects.filter(main=transfer, status__in=[TransferCashRebateDetail.DEFAULT, TransferCashRebateDetail.PENDING])
        for item in detail:
            transfer_detail_refresh(item)


def transfer_detail_refresh(detail):
    wx = WechatApplet.objects.filter().first()
    if not wx:
        raise Exception(u'小程序appid认证失败！')
    out_detail_no = detail.no or None
    out_batch_no = detail.main and detail.main.no or None
    t = Transfer(wx)
    code, message = t.transfer_query_out_detail_no(out_detail_no, out_batch_no)
    result = json.loads(message)
    if code != 200:
        raise Exception(u'转账明细[{}]查询失败！原因:{}'.format(out_detail_no, result))
    # 更新明细状态
    detail_id = result.get('detail_id')         # 微信明细单号
    detail_status = result.get('detail_status') # 明细装填  PROCESSING:转账中。正在处理中，转账结果尚未明确  SUCCESS:转账成功  FAIL:转账失败。需要确认失败原因后，再决定是否重新发起对该笔明细单的转账（并非整个转账批次单）
    fail_reason = result.get('fail_reason')     # 失败原因
    initiate_time = result.get('initiate_time') # 转账发起时间
    update_time = result.get('update_time')     # 明细更新时间

    if detail_id:
        detail.detail_no = detail_id
    if detail_status:
        if detail_status == 'PROCESSING':
            detail.status = TransferCashRebateDetail.PENDING
        elif detail_status == 'SUCCESS':
            detail.status = TransferCashRebateDetail.SUCCESS
            # 在这将收款人的余额减掉相应的金额
            # 转账已经成功了 就算是客户的余额是负数  也要统计成负数 转出去的钱不能返回了  所以只有在创建转账明细的时候要控制 转账金额不能大于客户余额
            CashTransferLog.addnew(detail)
        elif detail_status == 'FAIL':
            detail.status = TransferCashRebateDetail.FAIL

    if fail_reason:
        detail.fail_reason = fail_reason
    if initiate_time:
        detail.initiate_time = datetime.datetime.strptime(initiate_time, "%Y-%m-%dT%H:%M:%S+08:00")
    if update_time:
        detail.update_time = datetime.datetime.strptime(update_time, "%Y-%m-%dT%H:%M:%S+08:00")
    detail.save()
