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

import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.newfeifan.mall.module.distri.controller.admin.ptprofitlog.vo.PtProfitLogSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.ptprofitlog.PtProfitLogDO;
import cn.newfeifan.mall.module.distri.dal.mysql.ptprofit.PtProfitMapper;
import cn.newfeifan.mall.module.distri.dal.mysql.ptprofitlog.PtProfitLogMapper;
import cn.newfeifan.mall.module.distri.enums.CaclEnum;
import cn.newfeifan.mall.module.distri.service.ptprofitlog.PtProfitLogService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;

import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
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.integral.IntegralMapper;

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

/**
 * 推荐用户积分 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class IntegralServiceImpl implements IntegralService {

    @Resource
    private IntegralMapper integralMapper;
    @Resource
    private PtProfitLogMapper ptProfitLogMapper;

    @Resource
    private PtProfitLogService ptProfitLogService;

    @Resource
    private PtProfitMapper ptProfitMapper;

    @Override
    public Long createIntegral(IntegralSaveReqVO createReqVO) {
        // 插入
        IntegralDO integral = BeanUtils.toBean(createReqVO, IntegralDO.class);
        integral.setAccumulatedQuota(0L);
        integral.setAncestorQuota(0L);
        integralMapper.insert(integral);
        // 返回
        return integral.getId();
    }

    @Override
    public void updateIntegral(IntegralSaveReqVO updateReqVO) {
        // 校验存在
        validateIntegralExists(updateReqVO.getId());
        // 更新
        IntegralDO updateObj = BeanUtils.toBean(updateReqVO, IntegralDO.class);
        integralMapper.updateById(updateObj);
    }

    @Override
    public void deleteIntegral(Long id) {
        // 校验存在
        validateIntegralExists(id);
        // 删除
        integralMapper.deleteById(id);
    }

    private void validateIntegralExists(Long id) {
        if (integralMapper.selectById(id) == null) {
            throw exception(INTEGRAL_NOT_EXISTS);
        }
    }

    @Override
    public IntegralDO getIntegral(Long id) {
        return integralMapper.selectOne(new LambdaQueryWrapperX<IntegralDO>().eqIfPresent(IntegralDO::getUserId, id));
    }

    @Override
    public PageResult<IntegralDO> getIntegralPage(IntegralPageReqVO pageReqVO) {
        return integralMapper.selectPage(pageReqVO);
    }

    @Override
    public IntegralDO selectByUser(Long descendant) {
        return integralMapper.selectOne(new LambdaQueryWrapper<IntegralDO>().eq(IntegralDO::getUserId, descendant));
    }

    @Override
    public void saveBatch(List<IntegralSaveReqVO> integralSaveReqVOS) {
        List<IntegralDO> integralDOS = BeanUtils.toBean(integralSaveReqVOS, IntegralDO.class);
        integralDOS.forEach(k -> {
            k.setAccumulatedQuota(0L);
            k.setAncestorQuota(0L);
        });
        integralMapper.insertBatch(integralDOS);
    }

    @Override
    public void updateBatch(List<IntegralSaveReqVO> integralSaveReqVOS) {
        integralMapper.updateBatch(BeanUtils.toBean(integralSaveReqVOS, IntegralDO.class));
    }
    @Override
    public List<IntegralDO> selectAllUser() {

        return integralMapper.selectList();

    }

    @Override
    public IntegralDO getIntegralByUserId(Long userId) {
        return integralMapper.selectOne(new LambdaQueryWrapper<IntegralDO>()
                .eq(IntegralDO::getUserId, userId)
        );
    }

    @Override
    public void updateIntegralFreezeHighQuota(Long generateUserId, Long userId, CaclEnum caclEnum, Long totalFreezeHighQuota, Long tradeOrderId, String orderNum, LocalDateTime payTime) {
        try{
            IntegralDO integralDO = integralMapper.selectOne(new LambdaQueryWrapper<IntegralDO>().eq(IntegralDO::getUserId, userId));
            integralDO.setFreezeHighQuota(integralDO.getFreezeHighQuota() + totalFreezeHighQuota);
            integralMapper.updateById(integralDO);

            //记录用户的积分变动日志
            PtProfitLogDO ptProfitLogDO = PtProfitLogDO.builder()
                    .generateUserId(generateUserId)
                    .profitStatus(caclEnum.getType())
                    .orderId(tradeOrderId)
                    .orderNo(orderNum)
                    .build();
            ptProfitLogDO.setCreateTime(payTime);
            ptProfitLogDO.setUpdateTime(payTime);
            ptProfitLogMapper.insert(ptProfitLogDO);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public void updateIntegralFreezeHighQuota(Long generateUserId, Long userId, CaclEnum caclEnum, Long totalFreezeHighQuota, Long tradeOrderId, String orderNum) {
        IntegralDO integralDO = integralMapper.selectOne(new LambdaQueryWrapper<IntegralDO>().eq(IntegralDO::getUserId, userId));
        integralDO.setFreezeHighQuota(integralDO.getFreezeHighQuota() + totalFreezeHighQuota);
        integralMapper.updateById(integralDO);

        //记录用户的积分变动日志
        PtProfitLogSaveReqVO profitLogSaveReqVO = PtProfitLogSaveReqVO.builder()
                .generateUserId(generateUserId)
                .profitStatus(caclEnum.getType())
                .orderId(tradeOrderId)
                .orderNo(orderNum)
                .build();
        ptProfitLogService.createPtProfitLog(profitLogSaveReqVO);
    }

    @Override
    public void initializeIntegralHighQuotaTotal() {
        List<IntegralDO> integralDOS = integralMapper.selectList();
        for (IntegralDO integralDO : integralDOS) {
            List<PtProfitLogDO> ptProfitLogDOS = ptProfitLogMapper.selectList(new LambdaQueryWrapper<PtProfitLogDO>()
                    .eq(PtProfitLogDO::getGenerateUserId, integralDO.getUserId())
                    .eq(PtProfitLogDO::getProfitStatus, DIRECT_REFERRAL_QUOTA.getType())
            );
            integralMapper.updateById(integralDO);
            if(ptProfitLogDOS.size() > 1){
                System.out.println("用户编号:[" + integralDO.getUserId() + "]");
            }
        }
    }

    @Override
    public void updateUserIntegral(Long userId, CaclEnum caclEnum, Long payIntegral, Long tradeOrderId, String orderNum) {
        //退还订单支付过期积分
        IntegralDO integralDO = integralMapper.selectOne(new LambdaQueryWrapper<IntegralDO>().eq(IntegralDO::getUserId, userId));
        integralDO.setRedCurrentQuota(integralDO.getRedCurrentQuota() + payIntegral);

        integralMapper.updateById(integralDO);

        ptProfitLogService.addMessage(userId,userId,caclEnum,payIntegral,integralDO.getRedCurrentQuota(),0L,0L,null,tradeOrderId,orderNum);
    }

    /**
     * add by Ben
     * 修改用户积分
     *
     * @param generateUserId 要修改积分的用户
     * @param userId 要修改积分的用户
     * @param caclEnum 导致积分变化的事件类型枚举
     * @param amount 用户可用积分变化金额，可为负数
     * @param freezeAmount 用户冻结积分变化金额，可为负数
     * @return 返回是否执行成功。执行失败，通常是就是用户积分不足，没积分抵扣
     */
    @Override
    public Boolean updateUserIntegral(Long generateUserId,//导致产生积分变动的用户ID
                                      Long userId, CaclEnum caclEnum, Long amount, Long freezeAmount,
                                      Long tradeOrderId,
                                      String OrderNum
    ) {
        Boolean success = null;

        //修改用户积分钱包的积分
        int effectRowNum = ptProfitMapper.updateUserIntegral(amount,amount,freezeAmount,freezeAmount,userId);

        if (effectRowNum==1) {//如果成功修改积分记录
            success = true;

            //用户修改后的当前可用的钱包余额
            Long afterAmount = null;
            //用户修改后的冻结积分钱包余额
            Long afterFreezeAmount = null;

            //查询用户修改后的积分
            Map<String, Object> map = ptProfitMapper.selectUserIntegral(userId);
            Object currentQuotaObj = map.get("current_quota");
            Object freezeQuotaObj = map.get("freeze_quota");

            afterAmount = (Long)currentQuotaObj;
            afterFreezeAmount = (Long)freezeQuotaObj;

            if(afterAmount<0||afterFreezeAmount<0){
                throw new RuntimeException("用户钱包为负数：用户IO为"+userId+"的用户可用钱包为"+afterAmount+",冻结钱包为"+afterFreezeAmount);
            }

            //记录用户的积分变动日志
            ptProfitLogService.addMessage(generateUserId,//导致产生积分变动的用户ID
                    userId, caclEnum, amount, afterAmount,
                    freezeAmount, afterFreezeAmount,null,tradeOrderId,OrderNum);

        }else if(effectRowNum<1){//如果钱包积分不足，不够抵扣
            success = false;
        } else if (effectRowNum>1) {
            throw new RuntimeException("用户ID为"+userId+"的用户钱包不只一个！");
        }

        return success;
    }

    @Override
    public void calcIntegral() {

    }



}
