package cn.newfeifan.mall.module.distri.service.ordercalc;

import cn.newfeifan.mall.framework.common.util.json.JsonUtils;
import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.newfeifan.mall.module.distri.controller.admin.duser.vo.DuserSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.IntegralSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.ptprofit.vo.PtProfitSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.ptprofitlog.vo.PtProfitLogSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.orderpercentage.OrderPercentageDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.ptprofit.PtProfitDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.sharepath.SharePathDO;
import cn.newfeifan.mall.module.distri.enums.CaclEnum;
import cn.newfeifan.mall.module.distri.mq.message.order.DistriOrderMessage;
import cn.newfeifan.mall.module.distri.service.duser.DuserService;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.orderpercentage.OrderPercentageService;
import cn.newfeifan.mall.module.distri.service.partitioncrash.PartitionCrashService;
import cn.newfeifan.mall.module.distri.service.ptprofit.PtProfitService;
import cn.newfeifan.mall.module.distri.service.ptprofitlog.PtProfitLogService;
import cn.newfeifan.mall.module.distri.service.sharepath.SharePathService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.newfeifan.mall.module.distri.controller.admin.ordercalc.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.ordercalc.OrderCalcDO;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.util.object.BeanUtils;

import cn.newfeifan.mall.module.distri.dal.mysql.ordercalc.OrderCalcMapper;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.distri.constant.DistriConstants.PERCENT;
import static cn.newfeifan.mall.module.distri.constant.DistriConstants.THREE;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

/**
 * 订单产生数据计算 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class OrderCalcServiceImpl implements OrderCalcService {

    @Resource
    private OrderCalcMapper orderCalcMapper;

    @Resource
    private PtProfitService ptProfitService;

    @Resource
    private PtProfitLogService ptProfitLogService;

    @Resource
    @Lazy
    private SharePathService sharePathService;

    @Resource
    private OrderPercentageService orderPercentageService;

    @Resource
    @Lazy
    private DuserService duserService;

    @Resource
    @Lazy
    private IntegralService integralService;

    @Resource
    private PartitionCrashService partitionCrashService;

    @Override
    public Long createOrderCalc(OrderCalcSaveReqVO createReqVO) {
        // 插入
        OrderCalcDO orderCalc = BeanUtils.toBean(createReqVO, OrderCalcDO.class);
        orderCalcMapper.insert(orderCalc);
        // 返回
        return orderCalc.getId();
    }

    @Override
    public void updateOrderCalc(OrderCalcSaveReqVO updateReqVO) {
        // 校验存在
        validateOrderCalcExists(updateReqVO.getId());
        // 更新
        OrderCalcDO updateObj = BeanUtils.toBean(updateReqVO, OrderCalcDO.class);
        orderCalcMapper.updateById(updateObj);
    }

    @Override
    public void deleteOrderCalc(Long id) {
        // 校验存在
        validateOrderCalcExists(id);
        // 删除
        orderCalcMapper.deleteById(id);
    }

    private void validateOrderCalcExists(Long id) {
        if (orderCalcMapper.selectById(id) == null) {
            throw exception(ORDER_CALC_NOT_EXISTS);
        }
    }

    @Override
    public OrderCalcDO getOrderCalc(Long id) {
        return orderCalcMapper.selectById(id);
    }

    @Override
    public PageResult<OrderCalcDO> getOrderCalcPage(OrderCalcPageReqVO pageReqVO) {
        return orderCalcMapper.selectPage(pageReqVO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calc(List<DistriOrderMessage> tradeOrderDO) {

        // 获取到当前订单的所有人
        List<Long> userId = tradeOrderDO.stream().map(DistriOrderMessage::getUserId).collect(Collectors.toList());
        // 判断当前下单的人员是否有进入营销模块用户表, 如果没有的话, 需要初始化
        duserService.hasUserAndCreat(userId);
        // 判断当前下单人是否有有上级, 如果没有, 创建直推人关系
        sharePathService.createSharePathByUserId(userId);

        try {

            OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
            // 当前计算百分比模板
            String percentTemplate = JsonUtils.toJsonString(orderPercentageDO);

            calc(tradeOrderDO, orderPercentageDO, percentTemplate);

        } catch (Exception e) {

        } finally {
            // todo 计算当天用户的碰撞
            // 计算兄弟分区， 以及后代分区
            partitionCrashService.calcCrash(userId);
        }


    }

    @Override
    public List<OrderCalcDO> queryTodayCalcByUserIds(LocalDateTime todayStart, LocalDateTime todayEnd) {

        return   orderCalcMapper.selectList(new LambdaQueryWrapperX<OrderCalcDO>().betweenIfPresent(OrderCalcDO::getCreateTime,todayStart,todayEnd));

    }

    private void calc(List<DistriOrderMessage> tradeOrderDO, OrderPercentageDO orderPercentageDO, String percentTemplate) {

        // 给用户分组


        // 每个订单收益
        List<OrderCalcSaveReqVO> saveList = new ArrayList<>();
        // 平台收益
        List<PtProfitSaveReqVO> ptProfitSaveReqVOS = new ArrayList<>();
        // 平台收益日志
        List<PtProfitLogSaveReqVO> ptProfitLogSaveReqVOS = new ArrayList<>();
        // 修改用户钱包
        List<IntegralSaveReqVO> integralSaveReqVOS = new ArrayList<>();

        // todo 修改用户身价 如何从订单中获取身价?
        List<DuserSaveReqVO> duserSaveReqVOS = new ArrayList<>();

        PtProfitDO ptProfitDO = ptProfitService.getPtProfit();
        PtProfitDO finalPtProfitDO = ptProfitDO;
        tradeOrderDO.forEach(k -> {

            BigDecimal price = new BigDecimal(String.valueOf(k.getPrice()));
            BigDecimal costPrice = new BigDecimal(String.valueOf(k.getCostPrice()));
            BigDecimal productCount = new BigDecimal(String.valueOf(k.getProductCount()));

            // 计算
            // 计算利润: (价格 - 成本价格) * 产品数量
//            Integer profit = (k.getPrice() - k.getCostPrice()) * k.getProductCount();

            BigDecimal profit = price.subtract(costPrice).multiply(productCount);

            // 计算毛利: 利润 * 0.38
            BigDecimal grossProfit = profit.multiply(new BigDecimal(String.valueOf(orderPercentageDO.getGrossProfitPerc()))).setScale(4, RoundingMode.DOWN);

            // 计算推荐人额度: 毛利 * 0.35
            BigDecimal ancestorQuota = grossProfit.multiply(new BigDecimal(orderPercentageDO.getGrossProfitUserQuotaPerc())).setScale(4, RoundingMode.DOWN);

            // 计算直推人额度: 毛利 * 0.35
            BigDecimal descendantQuota = grossProfit.multiply(new BigDecimal(orderPercentageDO.getGrossProfitAncestorQuotaPerc())).setScale(4, RoundingMode.DOWN);

            // 计算合赢奖: 毛利 * 0.08
            BigDecimal bonusQuota = grossProfit.multiply(new BigDecimal(orderPercentageDO.getGrossProfitBonusQuotaPerc())).setScale(4, RoundingMode.DOWN);

            // 计算平台收益: 毛利 * 0.22
            BigDecimal platformQuota = grossProfit.multiply(new BigDecimal(orderPercentageDO.getGrossProfitPlatformQuotaPerc())).setScale(4, RoundingMode.DOWN);

            // 计算当前下单人的毛利的三倍
            BigDecimal highQuota = grossProfit.multiply(new BigDecimal("3")).setScale(4, RoundingMode.DOWN);

            // 乘以 10000 并转换为整数
            int grossProfitInt = grossProfit.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).intValueExact();
            int ancestorQuotaInt = ancestorQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).intValueExact();
            int descendantQuotaInt = descendantQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).intValueExact();
            int bonusQuotaInt = bonusQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).intValueExact();
            int platformQuotaInt = platformQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).intValueExact();
            int highQuotaInt = highQuota.multiply(new BigDecimal("10000")).setScale(0, RoundingMode.DOWN).intValueExact();


            // 获取当前下单人关系
            SharePathDO sharePath = getSharePath(k.getUserId());
            // 如果sharePath为空, 则说明没有直推人关系
            IntegralDO integralDOAncestor = integralService.selectByUser(sharePath.getAncestor());
            IntegralDO integralDO = integralService.selectByUser(sharePath.getDescendant());
            IntegralDO ptIntegral = integralService.selectByUser(1L);
            // ========== 汇总计算 =================
            OrderCalcSaveReqVO orderCalcSaveReqVO = OrderCalcSaveReqVO.builder()
                    .userId(k.getUserId())
                    .orderNo(k.getNo())
                    .orderId(k.getOrderId())
                    .cost(k.getCostPrice())
                    .price(k.getPrice())
                    .productCount(k.getProductCount())
                    .nickName(k.getNickName())
                    .name(k.getName())
                    .grossProfit(grossProfitInt)
                    .grossProfitUserQuota(ancestorQuotaInt)
                    .grossProfitAncestorQuota(descendantQuotaInt)
                    .grossProfitBonusQuota(bonusQuotaInt)
                    .grossProfitPlatformQuota(platformQuotaInt)
                    .percentTemplate(percentTemplate).build();
            saveList.add(orderCalcSaveReqVO);            // ========== 修改用户钱包 =================
            changeUserWallet(integralSaveReqVOS, integralDO, integralDOAncestor, ptIntegral, ancestorQuotaInt, descendantQuotaInt, highQuotaInt, grossProfitInt, platformQuotaInt);
            // ========== 修改平台信息 =================
            // 每个订单计算的过程
            // 增加平台收益
            // 平台服务费

            BigDecimal ptGrossAdd = new BigDecimal(finalPtProfitDO.getPtGrossAdd());
            BigDecimal ptAdd = new BigDecimal(finalPtProfitDO.getPtAdd());
            BigDecimal ptTotalAdd = new BigDecimal(finalPtProfitDO.getPtTotalAdd());
            BigDecimal bonusQuotaPerc = new BigDecimal(orderPercentageDO.getGrossProfitPerc());

            // 计算平台收益：毛利润减去合赢奖百分比后的金额
            BigDecimal one = BigDecimal.ONE;
            BigDecimal grossProfitAfterBonus = grossProfit.multiply(one.subtract(bonusQuotaPerc));
            BigDecimal newPtAdd = ptAdd.add(grossProfitAfterBonus);
            BigDecimal newPtGrossAdd = ptGrossAdd.add(platformQuota);

            // 计算平台总收益
            BigDecimal newPtTotal = ptTotalAdd.add(newPtGrossAdd).add(newPtAdd);

            // 换成整数
            int ptGrossAddInt = newPtGrossAdd.intValue();
            int ptAddInt = newPtAdd.intValue();
            int ptTotalInt = newPtTotal.intValue();

            PtProfitSaveReqVO ptProfitSaveReqVO = PtProfitSaveReqVO.builder().ptAdd(ptAddInt).ptGrossAdd(ptGrossAddInt).ptTotalAdd(ptTotalInt).build();
            ptProfitSaveReqVOS.add(ptProfitSaveReqVO);
            // ========== 增加日志记录 =================

            // 平台记录
            PtProfitLogSaveReqVO ptGrossAddLog = PtProfitLogSaveReqVO.builder().orderId(k.getOrderId()).profitStatus(CaclEnum.PLATFORM_SERVICE_FEE.getType()).orderNo(k.getNo()).amount(platformQuotaInt).afterAmount(ptProfitSaveReqVO.getPtGrossAdd()).percentTemplate(percentTemplate).build();

            PtProfitLogSaveReqVO ptAddLog = PtProfitLogSaveReqVO.builder().orderId(k.getOrderId()).profitStatus(CaclEnum.PLATFORM_REVENUE.getType()).orderNo(k.getNo()).amount(grossProfitAfterBonus.intValue()).afterAmount(ptProfitSaveReqVO.getPtAdd()).percentTemplate(percentTemplate).build();


            // 推荐人记录
            PtProfitLogSaveReqVO tjrLog = PtProfitLogSaveReqVO.builder().orderId(k.getOrderId()).profitStatus(CaclEnum.RECOMMENDED_PERSON_QUOTA.getType()).orderNo(k.getNo()).userId(sharePath.getAncestor()).amount(ancestorQuotaInt).afterAmount(integralDOAncestor.getCurrentQuota() + ancestorQuotaInt).percentTemplate(percentTemplate).build();


            // 直推人记录
            PtProfitLogSaveReqVO ztrLog = PtProfitLogSaveReqVO.builder().orderId(k.getOrderId()).profitStatus(CaclEnum.DIRECT_REFERRAL_QUOTA.getType()).orderNo(k.getNo()).userId(sharePath.getDescendant()).amount(descendantQuotaInt).afterAmount(integralDO.getCurrentQuota() + descendantQuotaInt).percentTemplate(percentTemplate).build();
            PtProfitLogSaveReqVO highQuotaLog = PtProfitLogSaveReqVO.builder().orderId(k.getOrderId()).profitStatus(CaclEnum.HIGH_QUOTA.getType()).orderNo(k.getNo()).userId(sharePath.getDescendant()).amount(highQuotaInt).afterAmount(integralDO.getHighQuota() + highQuotaInt).percentTemplate(percentTemplate).build();

            // 合赢奖记录
            PtProfitLogSaveReqVO hyjLog = PtProfitLogSaveReqVO.builder().orderId(k.getOrderId()).profitStatus(CaclEnum.TOGETHER_AWARD.getType()).orderNo(k.getNo()).amount(bonusQuotaInt).afterAmount(0).percentTemplate(percentTemplate).build();


            ptProfitLogSaveReqVOS.add(ptGrossAddLog);
            ptProfitLogSaveReqVOS.add(ptAddLog);
            ptProfitLogSaveReqVOS.add(tjrLog);
            ptProfitLogSaveReqVOS.add(ztrLog);
            ptProfitLogSaveReqVOS.add(hyjLog);
            ptProfitLogSaveReqVOS.add(highQuotaLog);


        });

        // 信息整合
        // 计算平台收益
        ptProfitDO = calcPtProfit(ptProfitDO, ptProfitSaveReqVOS);

        // 将信息存储到数据库中
        orderCalcMapper.insertBatch(BeanUtils.toBean(saveList, OrderCalcDO.class));
        ptProfitService.updatePtProfit(BeanUtils.toBean(ptProfitDO, PtProfitSaveReqVO.class));
        ptProfitLogService.saveBatch(ptProfitLogSaveReqVOS);
    }

    private PtProfitDO calcPtProfit(PtProfitDO ptProfitDO, List<PtProfitSaveReqVO> ptProfitSaveReqVOS) {

        int currentPtAdd = 0;
        int currentPtGrossAdd = 0;

        for (PtProfitSaveReqVO ptProfitSaveReqVO : ptProfitSaveReqVOS) {
            currentPtAdd = currentPtAdd + ptProfitSaveReqVO.getPtAdd();
            currentPtGrossAdd = currentPtGrossAdd + ptProfitSaveReqVO.getPtGrossAdd();
        }

        ptProfitDO.setPtAdd(ptProfitDO.getPtAdd() + currentPtAdd);
        ptProfitDO.setPtGrossAdd(ptProfitDO.getPtGrossAdd() + currentPtGrossAdd);
        ptProfitDO.setPtTotalAdd(currentPtAdd + currentPtGrossAdd + ptProfitDO.getPtTotalAdd());

        return ptProfitDO;
    }

    private static void addCaclDo(String percentTemplate, List<OrderCalcSaveReqVO> saveList, DistriOrderMessage k, Integer grossProfit, Integer ancestorQuota, Integer descendantQuota, Integer bonusQuota, Integer platformQuota) {
        OrderCalcSaveReqVO orderCalcSaveReqVO = OrderCalcSaveReqVO.builder()
                .userId(k.getUserId())
                .orderNo(k.getNo())
                .cost(k.getCostPrice())
                .price(k.getPrice())
                .grossProfit(grossProfit)
                .grossProfitUserQuota(ancestorQuota)
                .grossProfitAncestorQuota(descendantQuota)
                .grossProfitBonusQuota(bonusQuota)
                .grossProfitPlatformQuota(platformQuota)
                .percentTemplate(percentTemplate).build();
        saveList.add(orderCalcSaveReqVO);
    }

    private void changeUserWallet(List<IntegralSaveReqVO> integralSaveReqVOS, IntegralDO integralDO, IntegralDO integralDOAncestor, IntegralDO pt,
                                  Integer ancestorQuota, Integer descendantQuota, Integer highQuota, Integer ptA, Integer ptB) {
        // 修改用户钱包
        // 增加直推人额度
        integralDO.setHighQuota(integralDO.getHighQuota() + highQuota);
        integralDO.setCurrentQuota(integralDO.getCurrentQuota() + descendantQuota);


        // 增加推荐人额度
        integralDOAncestor.setCurrentQuota(integralDO.getCurrentQuota() + ancestorQuota);
        // 增加平台额度
        pt.setCurrentQuota(integralDO.getCurrentQuota() + ptA + ptB);

//        integralSaveReqVOS.add(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));
//        integralSaveReqVOS.add(BeanUtils.toBean(integralDOAncestor, IntegralSaveReqVO.class));

        integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));
        integralService.updateIntegral(BeanUtils.toBean(integralDOAncestor, IntegralSaveReqVO.class));
        integralService.updateIntegral(BeanUtils.toBean(pt, IntegralSaveReqVO.class));

    }


    // 获取当前订单的下单人的直推关系
    public SharePathDO getSharePath(Long userId) {
        return sharePathService.getSharePathByDescendant(userId);
    }


}