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

import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.IntegralSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.integralchangelog.vo.IntegralChangeLogSaveReqVO;
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.IntegralEnum;
import cn.newfeifan.mall.module.distri.enums.IntegralTypeEnum;
import cn.newfeifan.mall.module.distri.enums.ProfitTypeEnum;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.integralchangelog.IntegralChangeLogService;
import cn.newfeifan.mall.module.distri.service.orderpercentage.OrderPercentageService;
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 com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import cn.newfeifan.mall.module.distri.controller.admin.dailyawardrecords.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.dailyawardrecords.DailyAwardRecordsDO;
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.dailyawardrecords.DailyAwardRecordsMapper;

import java.util.*;
import java.util.stream.Collectors;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;
import static cn.newfeifan.mall.module.distri.enums.IntegralEnum.LUCKY_BONUS;

/**
 * 每日用户获得合赢奖记录 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
@Slf4j
public class DailyAwardRecordsServiceImpl implements DailyAwardRecordsService {

    @Resource
    private DailyAwardRecordsMapper dailyAwardRecordsMapper;

    @Resource
    private IntegralService integralService;

    @Resource
    private IntegralChangeLogService integralChangeLogService;

    @Resource
    private OrderPercentageService orderPercentageService;

    @Resource
    private SharePathService sharePathService;
    @Resource
    private PtProfitService ptProfitService;
    @Resource
    private PtProfitLogService ptProfitLogService;

    @Override
    public Long createDailyAwardRecords(DailyAwardRecordsSaveReqVO createReqVO) {
        // 插入
        DailyAwardRecordsDO dailyAwardRecords = BeanUtils.toBean(createReqVO, DailyAwardRecordsDO.class);
        dailyAwardRecordsMapper.insert(dailyAwardRecords);
        // 返回
        return dailyAwardRecords.getId();
    }

    @Override
    public void updateDailyAwardRecords(DailyAwardRecordsSaveReqVO updateReqVO) {
        // 校验存在
        validateDailyAwardRecordsExists(updateReqVO.getId());
        // 更新
        DailyAwardRecordsDO updateObj = BeanUtils.toBean(updateReqVO, DailyAwardRecordsDO.class);
        dailyAwardRecordsMapper.updateById(updateObj);
    }

    @Override
    public void deleteDailyAwardRecords(Long id) {
        // 校验存在
        validateDailyAwardRecordsExists(id);
        // 删除
        dailyAwardRecordsMapper.deleteById(id);
    }

    private void validateDailyAwardRecordsExists(Long id) {
        if (dailyAwardRecordsMapper.selectById(id) == null) {
            throw exception(DAILY_AWARD_RECORDS_NOT_EXISTS);
        }
    }

    @Override
    public DailyAwardRecordsDO getDailyAwardRecords(Long id) {
        return dailyAwardRecordsMapper.selectById(id);
    }

    @Override
    public PageResult<DailyAwardRecordsDO> getDailyAwardRecordsPage(DailyAwardRecordsPageReqVO pageReqVO) {
        return dailyAwardRecordsMapper.selectPage(pageReqVO);
    }

    @Override
    public void addDailyAwardRecords(Long userId, Long generateUserId, Long amount, Long logId, Long accumulatedQuotaAmount) {
        DailyAwardRecordsSaveReqVO createReqVO = DailyAwardRecordsSaveReqVO
                .builder()
                .userId(userId)
                .generateUserId(generateUserId)
                .amount(amount)
                .settled(false)
                .logId(logId)
                .accumulatedQuotaAmount(accumulatedQuotaAmount)
                .build();
        DailyAwardRecordsDO dailyAwardRecords = BeanUtils.toBean(createReqVO, DailyAwardRecordsDO.class);
        dailyAwardRecordsMapper.insert(dailyAwardRecords);
    }

    @Override
    public void transitionBonus() {
        //获取到当前7天前未结算的记录
        LambdaQueryWrapper<DailyAwardRecordsDO> wrapper = new LambdaQueryWrapper<DailyAwardRecordsDO>()
                .eq(DailyAwardRecordsDO::getSettled, false);
        //时间条件暂时关闭,因为现在的计算程序改为即算即用.后续如若改回,打开注释即可
//                .apply("date(create_time) <= DATE_SUB(now(), INTERVAL 7 DAY)");
//                .apply("date(create_time) <= DATE_SUB('2024-06-21', INTERVAL 7 DAY)");

        List<DailyAwardRecordsDO> dailyAwardRecordsSaveReqVOS = dailyAwardRecordsMapper.selectList(wrapper);

        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
        // 黄积分比例
        Double bonusYellowIntegral = Double.valueOf(orderPercentageDO.getBonusYellowIntegral());
        // 绿积分比例
        Double bonusGreenIntegral = Double.valueOf(orderPercentageDO.getBonusGreenIntegral());

        dailyAwardRecordsSaveReqVOS.forEach(dailyAwardRecordsDO -> {
            //获取用户钱包
            IntegralDO integralDO = integralService.getIntegralByUserId(dailyAwardRecordsDO.getUserId());
            //减去待确权
            integralDO.setFreezeQuota(integralDO.getFreezeQuota() - dailyAwardRecordsDO.getAmount());
            //加入可用
            long yellowIntegral = (long) (dailyAwardRecordsDO.getAmount() * bonusYellowIntegral);
            integralDO.setYellowCurrentQuota(integralDO.getYellowCurrentQuota() + yellowIntegral);
            long greenIntegral = (long) (dailyAwardRecordsDO.getAmount() * bonusGreenIntegral);
            integralDO.setGreenCurrentQuota(integralDO.getGreenCurrentQuota() + greenIntegral);
            integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));

            IntegralChangeLogSaveReqVO yellowLog = IntegralChangeLogSaveReqVO.builder()
                    .userId(integralDO.getUserId())
                    .integralPoints(yellowIntegral)
                    .practicalIntegralPoints(yellowIntegral)
                    .afterIntegralPoints(integralDO.getYellowCurrentQuota())
                    .maxAvailablePointsAmount(-dailyAwardRecordsDO.getAmount())
                    .afterMaxAvailablePointsAmount(integralDO.getHighQuota())
                    .accumulatedQuotaAmount(dailyAwardRecordsDO.getAccumulatedQuotaAmount())
                    .integralStatus(IntegralEnum.TEAM_BONUS.getType())
                    .integralType(IntegralTypeEnum.YELLOW_INTEGRAL.getType())
                    .build();

            IntegralChangeLogSaveReqVO greenLog = IntegralChangeLogSaveReqVO.builder()
                    .userId(integralDO.getUserId())
                    .integralPoints(greenIntegral)
                    .practicalIntegralPoints(greenIntegral)
                    .afterIntegralPoints(integralDO.getGreenCurrentQuota())
                    .integralStatus(IntegralEnum.TEAM_BONUS.getType())
                    .integralType(IntegralTypeEnum.GREEN_INTEGRAL.getType())
                    .build();
            integralChangeLogService.saveBatch(Arrays.asList(yellowLog, greenLog));

            dailyAwardRecordsDO.setSettled(true);
            dailyAwardRecordsMapper.updateById(dailyAwardRecordsDO);
        });
    }

    @Override
    public void calcLucky() {
        List<DailyAwardRecordsDO> VOS = dailyAwardRecordsMapper.selectList(new LambdaQueryWrapper<DailyAwardRecordsDO>()
                .eq(DailyAwardRecordsDO::getCalcLucky, false));

        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
        // 黄积分比例
        Double bonusYellowIntegral = Double.valueOf(orderPercentageDO.getBonusYellowIntegral());
        // 绿积分比例
        Double bonusGreenIntegral = Double.valueOf(orderPercentageDO.getBonusGreenIntegral());
        // 幸运奖比例
        Double grossProfitLuckyQuotaPerc = Double.valueOf(orderPercentageDO.getGrossProfitLuckyQuotaPerc());

        // 获取所有用户
        List<SharePathDO> sharePathDOS = sharePathService.selectList();
        // 获取平台钱包
        PtProfitDO ptProfit = ptProfitService.getPtProfit();

        List<IntegralChangeLogSaveReqVO> changeLogList = new ArrayList<>();
        List<PtProfitLogSaveReqVO> ptProfitLogList = new ArrayList<>();
        List<IntegralDO> integralList = new ArrayList<>();

        for (SharePathDO user : sharePathDOS) {// 获取用户推荐了多少个用户
            Integer peopleNumber = sharePathService.getReferrerNumber(user.getUserId());

            // 没有推荐人数不计算
            if (peopleNumber == 0) {
                continue;
            } else if (peopleNumber >= 20) {
                peopleNumber = 20;
            }

            // 获取到当前用户的所有下层用户
            List<Long> userIds = sharePathService.getUserIds(user.getUserId(), user.getDepth() + peopleNumber);

            Long amount = 0L;
            List<DailyAwardRecordsDO> DOS = VOS.stream()
                    .filter(record -> userIds.contains(record.getUserId()))
                    .collect(Collectors.toList());
            if (DOS.isEmpty()) continue;     // 没有获得团队奖用户不计算

            for (DailyAwardRecordsDO dailyAwardRecordsDO : DOS) {
                amount += dailyAwardRecordsDO.getAmount();
            }

            if (amount == 0) continue;
            // 幸运奖只获取到团队奖的5%(可调)
            amount = (long) (amount * grossProfitLuckyQuotaPerc);
            // 获取用户钱包
            IntegralDO integral = integralService.getIntegral(user.getUserId());
            // 用户峰值
            Long highQuota = integral.getHighQuota();
            // 超出幸运奖
            Long exceedAmount = 0L;

            if (highQuota < amount) {
                exceedAmount = highQuota;
                amount = highQuota;
            }

            Long yellowIntegral = (long) (amount * bonusYellowIntegral);
            Long greenIntegral = (long) (amount * bonusGreenIntegral);

            log.info("{}-用户获得了幸运奖{}层 :￥{}", integral.getUserName(), user.getDepth(),amount);

            // 增加用户积分
            integral.setHighQuota(integral.getHighQuota() - amount);
            integral.setYellowCurrentQuota(integral.getYellowCurrentQuota() + yellowIntegral);
            integral.setGreenCurrentQuota(integral.getGreenCurrentQuota() + greenIntegral);
            integral.setLuckyQuota(integral.getLuckyQuota() + amount);

            integralList.add(integral);

            IntegralChangeLogSaveReqVO yellowLog = IntegralChangeLogSaveReqVO.builder()
                    .userId(user.getUserId())
                    .integralPoints(yellowIntegral)
                    .practicalIntegralPoints(yellowIntegral)
                    .afterIntegralPoints(integral.getYellowCurrentQuota())
                    .maxAvailablePointsAmount(-amount)
                    .afterMaxAvailablePointsAmount(integral.getHighQuota())
                    .luckyQuotaAmount(exceedAmount)
                    .integralStatus(LUCKY_BONUS.getType())
                    .integralType(IntegralTypeEnum.YELLOW_INTEGRAL.getType())
                    .build();

            IntegralChangeLogSaveReqVO greenLog = IntegralChangeLogSaveReqVO.builder()
                    .userId(user.getUserId())
                    .integralPoints(greenIntegral)
                    .practicalIntegralPoints(greenIntegral)
                    .afterIntegralPoints(integral.getGreenCurrentQuota())
                    .integralStatus(LUCKY_BONUS.getType())
                    .integralType(IntegralTypeEnum.GREEN_INTEGRAL.getType())
                    .build();
            changeLogList.add(yellowLog);
            changeLogList.add(greenLog);

            // 扣减平台钱包
            ptProfit.setPtGrossAdd(ptProfit.getPtGrossAdd() - amount);
            ptProfit.setPtTotalAdd(ptProfit.getPtTotalAdd() - amount);

            PtProfitLogSaveReqVO log = PtProfitLogSaveReqVO.builder()
                    .generateUserId(user.getUserId())
                    .amount(-amount)
                    .afterAmount(ptProfit.getPtGrossAdd())
                    .percentTemplate(JSON.toJSONString(orderPercentageDO))
                    .profitType(ProfitTypeEnum.PT_PROFIT.getType())
                    .profitStatus(LUCKY_BONUS.getType())
                    .build();
            ptProfitLogList.add(log);
        }
        // 修改pt钱包
        ptProfitService.updatePtProfit(BeanUtils.toBean(ptProfit, PtProfitSaveReqVO.class));

        integralService.updateBatch(BeanUtils.toBean(integralList, IntegralSaveReqVO.class));

        // 记录日志
        ptProfitLogService.saveBatch(ptProfitLogList);
        integralChangeLogService.saveBatch(changeLogList);

        // 将信息保存为已计算幸运奖
        VOS.forEach(v -> v.setCalcLucky(true));
        dailyAwardRecordsMapper.updateBatch(VOS);
    }

}