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

import cn.newfeifan.mall.framework.common.exception.ErrorCode;
import cn.newfeifan.mall.module.distri.constant.DistriConstants;
import cn.newfeifan.mall.module.distri.controller.admin.consumptionchangelog.vo.ConsumptionChangeLogSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.IntegralSaveReqVO;
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.enums.ConsumptionEnum;
import cn.newfeifan.mall.module.distri.service.consumptionchangelog.ConsumptionChangeLogService;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.orderpercentage.OrderPercentageService;
import cn.newfeifan.mall.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
import cn.newfeifan.mall.module.member.dal.dataobject.user.MemberUserDO;
import cn.newfeifan.mall.module.member.service.user.MemberUserService;
import cn.newfeifan.mall.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.newfeifan.mall.module.system.controller.admin.auth.vo.AuthSmsSendReqVO;
import cn.newfeifan.mall.module.system.enums.sms.SmsSceneEnum;
import cn.newfeifan.mall.module.system.service.sms.SmsCodeService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

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

import cn.newfeifan.mall.module.distri.controller.admin.consumptiontopuplog.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.consumptiontopuplog.ConsumptionTopUpLogDO;
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.consumptiontopuplog.ConsumptionTopUpLogMapper;

import java.util.List;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.newfeifan.mall.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.newfeifan.mall.module.distri.enums.ErrorCodeConstants.*;

/**
 * 平台消费分充值记录 Service 实现类
 *
 * @author 非繁人
 */
@Service
@Validated
public class ConsumptionTopUpLogServiceImpl implements ConsumptionTopUpLogService {

    @Resource
    private ConsumptionTopUpLogMapper consumptionTopUpLogMapper;

    @Resource
    private OrderPercentageService orderPercentageService;

    @Resource
    private IntegralService integralService;

    @Resource
    private ConsumptionChangeLogService consumptionChangeLogService;

    @Resource
    private SmsCodeService smsCodeService;
    @Resource
    private MemberUserService memberUserService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createConsumptionTopUpLog(ConsumptionTopUpLogSaveReqVO createReqVO) {
        // 充值的额度
        Long agentQuota = createReqVO.getConsumptionPoints();
        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
        // 充值额度校验
        quotaVerify(createReqVO.getUserId(), createReqVO.getConsumptionPoints(), orderPercentageDO);

        // 短信验证码校验
        smsCodeService.useSmsCode(createReqVO.getSmsCodeUseReqDTO().setUsedIp(getClientIP()));

        // 额度放大百万倍,存储需要(方便换算),和积分一样
        createReqVO.setConsumptionPoints(createReqVO.getConsumptionPoints() * DistriConstants.MILLION);

        // 充值倍率
        if (createReqVO.getConsumptionPoints() >= Long.parseLong(orderPercentageDO.getTriggerMagnificationPoints()) * DistriConstants.MILLION) {
            createReqVO.setPracticalConsumptionPoints((long) (createReqVO.getConsumptionPoints() * Double.parseDouble(orderPercentageDO.getConsumptionMagnification())));
        } else {
            createReqVO.setPracticalConsumptionPoints(createReqVO.getConsumptionPoints());
        }


        // 插入
        ConsumptionTopUpLogDO consumptionTopUpLog = BeanUtils.toBean(createReqVO, ConsumptionTopUpLogDO.class);
        consumptionTopUpLogMapper.insert(consumptionTopUpLog);

        // 修改用户钱包
        IntegralDO integralDO = integralService.selectByUser(consumptionTopUpLog.getUserId());
        integralDO.setConsumptionPoints(integralDO.getConsumptionPoints() + consumptionTopUpLog.getPracticalConsumptionPoints());
        integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));

        // 记录用户消费分变动日志
        consumptionChangeLogService.createConsumptionChangeLog(ConsumptionChangeLogSaveReqVO.builder()
                .userId(consumptionTopUpLog.getUserId())
                .consumptionPoints(consumptionTopUpLog.getPracticalConsumptionPoints())
                .afterConsumptionPoints(integralDO.getConsumptionPoints())
                .consumptionStatus(ConsumptionEnum.PT_TOP_TUP.getType())
                .practicalConsumptionPoints(consumptionTopUpLog.getConsumptionPoints())
                .generateUserId(getLoginUserId())
                .build());

        // 发送短信通知用户充值成功
        MemberUserDO user = memberUserService.getUser(consumptionTopUpLog.getUserId());
        smsCodeService.sendSmsCode(SmsCodeSendReqDTO.builder()
                .mobile(user.getMobile())
                .scene(SmsSceneEnum.CONSUMPTION_POINTS_TOP_UP.getScene())
                .createIp(getClientIP())
                .build());

        // 当单笔充值大于设定金额时,将用户设置为代理商
        if(agentQuota >= Long.parseLong(orderPercentageDO.getAgentQuota()) && !user.getAgent()){
            user.setAgent(true);
            memberUserService.updateUser(BeanUtils.toBean(user, MemberUserUpdateReqVO.class));
        }

        // 返回
        return consumptionTopUpLog.getId();
    }

    /**
     * 校验充值额度
     *
     * @param userId            充值用户
     * @param consumptionPoints 额度
     * @param orderPercentageDO 设定额度
     */
    private void quotaVerify(Long userId, Long consumptionPoints, OrderPercentageDO orderPercentageDO) {
        // 金额不小于1就行
        if (consumptionPoints < 1) {
            throw exception(new ErrorCode(1_002_030_035, "充值额度不能小于1"));
        }

//        // 充值额度校验
//        Long quota = Long.parseLong(orderPercentageDO.getFollowUpConsumption());      // 后续充值
//        if (consumptionTopUpLogMapper.selectList(ConsumptionTopUpLogDO::getUserId, userId).isEmpty()) {
//            // 首次充值
//            quota = Long.parseLong(orderPercentageDO.getFirstTopUpConsumption());
//        }
//        if (consumptionPoints < quota) {
//            ErrorCode ERROR = new ErrorCode(1_002_030_035, "充值的额度不能小于规定额度");
//            throw exception(ERROR);
//        }
    }

    @Override
    public void updateConsumptionTopUpLog(ConsumptionTopUpLogSaveReqVO updateReqVO) {
        // 校验存在
        validateConsumptionTopUpLogExists(updateReqVO.getId());
        // 更新
        ConsumptionTopUpLogDO updateObj = BeanUtils.toBean(updateReqVO, ConsumptionTopUpLogDO.class);
        consumptionTopUpLogMapper.updateById(updateObj);
    }

    private void validateConsumptionTopUpLogExists(Long id) {
        if (consumptionTopUpLogMapper.selectById(id) == null) {
            throw exception(CONSUMPTION_TOP_UP_LOG_NOT_EXISTS);
        }
    }

    @Override
    public ConsumptionTopUpLogDO getConsumptionTopUpLog(Long id) {
        return consumptionTopUpLogMapper.selectById(id);
    }

    @Override
    public PageResult<ConsumptionTopUpLogDO> getConsumptionTopUpLogPage(ConsumptionTopUpLogPageReqVO pageReqVO) {
        return consumptionTopUpLogMapper.selectPage(pageReqVO);
    }

    @Override
    public ConsumptionInfoVO isFirstConsumption(Long userId) {
        List<ConsumptionTopUpLogDO> consumptionTopUpLogDOS = consumptionTopUpLogMapper.selectList(ConsumptionTopUpLogDO::getUserId, userId);

        ConsumptionInfoVO build = ConsumptionInfoVO.builder().build();
        OrderPercentageDO orderPercentageDO = orderPercentageService.queryStatus();
        if (consumptionTopUpLogDOS.isEmpty()) {
            build.setIsFirstConsumption(true);
            build.setMinimumConsumptionPoints(Long.valueOf(orderPercentageDO.getFirstTopUpConsumption()));
        } else {
            build.setIsFirstConsumption(false);
            build.setMinimumConsumptionPoints(Long.valueOf(orderPercentageDO.getFollowUpConsumption()));
        }
        build.setConsumptionMagnification(orderPercentageDO.getConsumptionMagnification());
        build.setTriggerMagnificationPoints(orderPercentageDO.getTriggerMagnificationPoints());
        return build;
    }

    @Override
    public List<ConsumptionTopUpLogDO> selectList() {
        return consumptionTopUpLogMapper.selectList();
    }

    @Override
    public PtTopUpWithUserTopUpRespVO ptTopUpWithUserTopUpList() {
        return PtTopUpWithUserTopUpRespVO.builder()
                .topUpList(consumptionTopUpLogMapper.ptTopUpWithUserTopUpList())
                .totalConsumptionPoints(consumptionTopUpLogMapper.getTotalConsumptionPoints())
                .build();
    }


}