package com.jeequan.jeepay.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.applyment.ApplymentBasicInfo;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.db.entity.*;
import com.jeequan.jeepay.model.MarketRed;
import com.jeequan.jeepay.model.RedPacketAccountOperate;
import com.jeequan.jeepay.service.mapper.RedPacketAccountMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author [mybatis plus generator]
 * @since 2024-01-17
 */
@Service
@Slf4j
@Transactional
public class RedPacketAccountService extends ServiceImpl<RedPacketAccountMapper, RedPacketAccount> {

    @Autowired
    private RedPacketRuleService redPacketRuleService;

    @Autowired
    private RedPacketInfoService redPacketInfoService;

    @Autowired
    private RedPacketAccountDetailService redPacketAccountDetailService;

    @Autowired
    private PayOrderService payOrderService;

    @Autowired
    private TransferOrderService transferOrderService;

    @Autowired
    private MchApplymentService mchApplymentService;

    @Autowired
    private BankBranchAlipayService bankBranchAlipayService;


    /**
     * 统计
     * @param wrapper
     * @return
     */
    public Map<String, Object> stsCount(Wrapper<RedPacketAccount> wrapper) {
        return baseMapper.stsCount(wrapper);
    }

    /**
     * 根据付款用户id以及门店id获取用户红包账户
     * @param payUserId
     * @param storeId
     * @return
     */

    public RedPacketAccount getByStorePayUserId(String payUserId,String storeId) {
        return baseMapper.getByStorePayUserId(payUserId,storeId);
    }

    public void upAccountBanlace(String accountId, Long changeAmt) {
        baseMapper.upAccountBanlace(accountId,changeAmt);
    }

    /**
     * 红包账户
     * @param payOrder
     */
    public MarketRed redAccount(PayOrder payOrder) {
        //只有支付包和微信交易才能创建红包
        if(CS.PAY_WAY_CODE_TYPE.WECHAT.equals(payOrder.getWayCodeType()) || CS.PAY_WAY_CODE_TYPE.ALIPAY.equals(payOrder.getWayCodeType())){
            boolean isCheck = redPacketRuleService.isCheckStoreRedRule(payOrder.getMchNo(),payOrder.getStoreId());
            if(isCheck){
                RedPacketAccountOperate operate = new RedPacketAccountOperate(payOrder,RedPacketAccountDetail.PAYMENT);
                return upAccount(operate);
            }
        }
        return null;
    }

    /**
     * 账户变更
     * @param operate
     */
    public synchronized MarketRed upAccount(RedPacketAccountOperate operate) {
        List<RedPacketAccountDetail> list = redPacketAccountDetailService.getByFlowNoType(operate.getFlowNo());
        if(!list.isEmpty()){
            return null;
        }
        if(RedPacketAccountDetail.PAYMENT == operate.getType()){
            MarketRed marketRed = new MarketRed();
            RedPacketRule rule = redPacketRuleService.getRuleByMchStrore(operate.getMchNo(), operate.getStoreId());
            //如果没有配置门店红包规则 则跳过
            if(rule == null || CS.NO == rule.getState()){
                return null;
            }
            BigDecimal scale = rule.getMarketScale().compareTo(BigDecimal.TEN) >= 0 ? rule.getMarketScale().divide(BigDecimal.valueOf(100)) : rule.getMarketScale().divide(BigDecimal.TEN);
            marketRed.setMarketScale(scale);
            BigDecimal calcScale = BigDecimal.ONE.subtract(scale);
            //如果之前没有账户 那么就创建账户 并且增加余额 增加一条红包发放记录 增加一条红包变更数据
            RedPacketAccount packetAccount = getByStorePayUserId(operate.getPayUserId(),operate.getStoreId());
            if(packetAccount == null){
                BigDecimal userPerkScale = rule.getUserPerkScale();
                Date expireTime = DateUtil.endOfDay(DateUtil.date().offset(DateField.MONTH,rule.getExpireNumber()));
                Long changeAmt = new BigDecimal(operate.getOrderAmt()).multiply(userPerkScale).setScale(0, RoundingMode.HALF_EVEN).longValue();
                packetAccount = new RedPacketAccount(operate,changeAmt);
                RedPacketInfo packetInfo = new RedPacketInfo(packetAccount,operate,operate.getOrderAmt(),changeAmt,rule.getMarketScale(),expireTime);
                packetInfo.setActualAmt(operate.getOrderAmt());
                RedPacketAccountDetail accountDetail = new RedPacketAccountDetail(packetAccount,operate,BigDecimal.ZERO.longValue(),changeAmt);
                save(packetAccount);
                redPacketInfoService.save(packetInfo);
                redPacketAccountDetailService.save(accountDetail);
                BigDecimal divAmt = BigDecimal.valueOf(operate.getOrderAmt()).multiply(calcScale).setScale(0, RoundingMode.HALF_EVEN);
                if(divAmt.compareTo(BigDecimal.ZERO) > 0){
                    payOrderService.updateExtDivAmt(operate.getFlowNo(),divAmt.longValue());
                }
                marketRed.setAmount(operate.getOrderAmt());
                marketRed.setFindAmt(packetInfo.getFindAmt());
                marketRed.setDiscountAmt(operate.getDiscountAmt());
                marketRed.setExtDivAmt(divAmt.longValue());
            }else{
                //则重新发放一个红包
                BigDecimal userPerkScale = rule.getUserPerkScale();
                Date expireTime = DateUtil.endOfDay(DateUtil.date().offset(DateField.MONTH,rule.getExpireNumber()));
                BigDecimal changeAmt = new BigDecimal(operate.getOrderAmt()).multiply(userPerkScale).setScale(0, RoundingMode.HALF_EVEN);
                RedPacketInfo redPacketInfo = redPacketInfoService.getRedPaketData(packetAccount.getMchNo(),packetAccount.getStoreId(),packetAccount.getPayUserId());
                if(redPacketInfo == null){
                    RedPacketInfo packetInfo = new RedPacketInfo(packetAccount,operate,operate.getOrderAmt(),changeAmt.longValue(),rule.getMarketScale(),expireTime);
                    packetInfo.setActualAmt(operate.getOrderAmt());
                    RedPacketAccountDetail accountDetail = new RedPacketAccountDetail(packetAccount,operate,packetAccount.getBalance(),changeAmt.longValue());
                    redPacketInfoService.save(packetInfo);
                    redPacketAccountDetailService.save(accountDetail);
                    upAccountBanlace(packetAccount.getAccountId(),changeAmt.longValue());
                    BigDecimal divAmt = BigDecimal.valueOf(operate.getOrderAmt()).multiply(calcScale).setScale(0, RoundingMode.HALF_EVEN);
                    if(divAmt.compareTo(BigDecimal.ZERO) > 0){
                        payOrderService.updateExtDivAmt(operate.getFlowNo(),divAmt.longValue());
                    }
                    marketRed.setAmount(operate.getOrderAmt());
                    marketRed.setFindAmt(packetInfo.getFindAmt());
                    marketRed.setDiscountAmt(operate.getDiscountAmt());
                    marketRed.setExtDivAmt(divAmt.longValue());
                }else{
                    //如果当前订单优惠金额大于或者等于红包金额
                    Long discountAmt = operate.getDiscountAmt();
                    //如果订单没有优惠金额 则直接跳过
                    if(discountAmt == null || discountAmt == BigDecimal.ZERO.longValue()){
                        return null;
                    }
                    //计算正常实际优惠金额
                    BigDecimal useAmt = BigDecimal.valueOf(redPacketInfo.getRewardAmt() - redPacketInfo.getUseAmt());
                    //如果当前优惠金额大于或等于红包的可使用余额 则超出的部分继续发放下一轮红包 并且状态改成 已使用
                    if(discountAmt.longValue() >= useAmt.longValue()){
                        redPacketInfo.setState(RedPacketInfo.YES_USE);
                        redPacketInfo.setUpdatedAt(new Date());
                        redPacketInfo.setActualAmt(BigDecimal.ZERO.longValue());
                        redPacketInfo.setUseAmt(redPacketInfo.getRewardAmt());
                        //修改红包为已使用状态 同时生成一条 红包的账户变动明细
                        redPacketInfoService.updateById(redPacketInfo);
                        RedPacketAccountDetail accountDetail = new RedPacketAccountDetail(packetAccount,operate,packetAccount.getBalance(),useAmt.negate().longValue());
                        accountDetail.setType(RedPacketAccountDetail.DEDUCT);
                        redPacketAccountDetailService.save(accountDetail);
                        upAccountBanlace(packetAccount.getAccountId(),useAmt.longValue());
                        BigDecimal platScale = rule.getPlatScale().compareTo(BigDecimal.TEN) < 0 ? rule.getPlatScale().divide(BigDecimal.TEN) : rule.getPlatScale().divide(BigDecimal.valueOf(100));
                        BigDecimal calcRedFindScale = BigDecimal.ONE.subtract(platScale);
                        BigDecimal maxMaketRedAmt = useAmt.divide(calcRedFindScale,0,BigDecimal.ROUND_DOWN);
                        BigDecimal sfAmt = new BigDecimal(operate.getOrderAmt()).subtract(useAmt);
                        marketRed.setAmount(operate.getOrderAmt());
                        marketRed.setFindAmt(sfAmt.longValue());
                        marketRed.setDiscountAmt(useAmt.longValue());
                        BigDecimal orderAmt = new BigDecimal(operate.getOrderAmt());
                        marketRed.setExtDivAmt(BigDecimal.ZERO.longValue());
                        if(orderAmt.compareTo(maxMaketRedAmt) > 0){
                            //这个金额需要进行分账 按照当前比例进行分账
                            BigDecimal calcRedAmt = orderAmt.subtract(maxMaketRedAmt);
                            //这个金额按照固定的比例算折扣
                            BigDecimal extDivAmt = calcRedAmt.multiply(calcScale).setScale(0, RoundingMode.HALF_EVEN);
                            if(extDivAmt.compareTo(BigDecimal.ZERO) > 0){
                                payOrderService.updateExtDivAmt(operate.getFlowNo(),extDivAmt.longValue());
                                marketRed.setExtDivAmt(extDivAmt.longValue());
                            }
                            BigDecimal fkAmt = calcRedAmt.multiply(rule.getUserPerkScale()).setScale(0,RoundingMode.HALF_EVEN);
                            if(fkAmt.compareTo(BigDecimal.ZERO) > 0){
                                RedPacketInfo packetInfo = new RedPacketInfo(packetAccount,operate,sfAmt.longValue(),fkAmt.longValue(),rule.getMarketScale(),expireTime);
                                packetInfo.setActualAmt(calcRedAmt.longValue());
                                redPacketInfoService.save(packetInfo);
                                RedPacketAccountDetail exAccountDetail = new RedPacketAccountDetail(packetAccount,operate,BigDecimal.ZERO.longValue(), fkAmt.longValue());
                                redPacketAccountDetailService.save(exAccountDetail);
                                upAccountBanlace(packetAccount.getAccountId(), fkAmt.negate().longValue());
                            }
                        }
                    }else{
                        BigDecimal calcAmt = BigDecimal.valueOf(discountAmt);
                        //如果优惠金额小于或等于红包账户余额 就消减红余额 和账户红包余额 并且插入一条红包变更记录
                        redPacketInfo.setState(RedPacketInfo.IN_USE);
                        redPacketInfo.setUpdatedAt(new Date());
                        redPacketInfo.setActualAmt(BigDecimal.ZERO.longValue());
                        redPacketInfo.setUseAmt(BigDecimal.valueOf(redPacketInfo.getUseAmt()).add(calcAmt).longValue());
                        redPacketInfoService.updateById(redPacketInfo);
                        RedPacketAccountDetail accountDetail = new RedPacketAccountDetail(packetAccount,operate,packetAccount.getBalance(),calcAmt.negate().longValue());
                        accountDetail.setType(RedPacketAccountDetail.DEDUCT);
                        redPacketAccountDetailService.save(accountDetail);
                        upAccountBanlace(packetAccount.getAccountId(),calcAmt.longValue());
                        marketRed.setAmount(operate.getOrderAmt());
                        marketRed.setFindAmt(operate.getOrderAmt()-operate.getDiscountAmt());
                        marketRed.setDiscountAmt(operate.getDiscountAmt());
                        marketRed.setExtDivAmt(BigDecimal.ZERO.longValue());
                    }
                }
            }
            return marketRed;
        }else if (RedPacketAccountDetail.REFUND == operate.getType()){
            throw new BizException("不支持当前操作");
        }else{
            return null;
        }
    }
}
