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

import cn.newfeifan.mall.framework.common.exception.ErrorCode;
import cn.newfeifan.mall.module.distri.constant.DistriConstants;
import cn.newfeifan.mall.module.distri.controller.app.consumptionchangelog.vo.ConsumptionChangeLogSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.app.consumptiontransferlog.vo.ConsumptionTransferLogPageReqVO;
import cn.newfeifan.mall.module.distri.controller.app.consumptiontransferlog.vo.ConsumptionTransferLogSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.app.integral.vo.IntegralSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
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.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.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.dal.dataobject.consumptiontransferlog.ConsumptionTransferLogDO;
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.consumptiontransferlog.ConsumptionTransferLogMapper;

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 ConsumptionTransferLogServiceImpl implements ConsumptionTransferLogService {

    @Resource
    private ConsumptionTransferLogMapper consumptionTransferLogMapper;

    @Resource
    private SmsCodeService smsCodeService;

    @Resource
    private IntegralService integralService;

    @Resource
    private ConsumptionChangeLogService consumptionChangeLogService;

    @Resource
    private MemberUserService memberUserService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createConsumptionTransferLog(ConsumptionTransferLogSaveReqVO createReqVO) {
        // 自己不能转账自己
        Long loginUserId = getLoginUserId();
        if (loginUserId != null && loginUserId.equals(createReqVO.getRecipientUserId())) {
            ErrorCode ERROR = new ErrorCode(1_002_030_037, "自己不能转账给自己");
            throw exception(ERROR);
        }

        // 短信验证码校验
        smsCodeService.useSmsCode(createReqVO.getSmsCodeUseReqDTO().setUsedIp(getClientIP()));
        // 消费分转成数据库存储的单位
        createReqVO.setConsumptionPoints(createReqVO.getConsumptionPoints() * DistriConstants.INTEGRAL_PAGE2DB);
        createReqVO.setTransferUserId(loginUserId);
        MemberUserDO user = memberUserService.getUser(loginUserId);
        createReqVO.setTransferUserName(user.getUsername());

        // 转让人钱包
        IntegralDO transferIntegral = integralService.selectByUser(createReqVO.getTransferUserId());
        transferIntegral.setConsumptionPoints(transferIntegral.getConsumptionPoints() - createReqVO.getConsumptionPoints());
        integralService.updateIntegral(BeanUtils.toBean(transferIntegral, IntegralSaveReqVO.class));
        // 接收人钱包
        IntegralDO recipientIntegral = integralService.selectByUser(createReqVO.getRecipientUserId());

        // 记录变动日志
        consumptionChangeLogService.createConsumptionChangeLog(
                ConsumptionChangeLogSaveReqVO.builder()
                        .userId(transferIntegral.getUserId())
                        .consumptionPoints(-createReqVO.getConsumptionPoints())
                        .afterConsumptionPoints(transferIntegral.getConsumptionPoints())
                        .consumptionStatus(ConsumptionEnum.CONSUMPTION_TRANSFER.getType())
                        .generateUserId(recipientIntegral.getUserId())
                        .build()
        );

        recipientIntegral.setConsumptionPoints(recipientIntegral.getConsumptionPoints() + createReqVO.getConsumptionPoints());
        integralService.updateIntegral(BeanUtils.toBean(recipientIntegral, IntegralSaveReqVO.class));

        // 记录变动日志
        consumptionChangeLogService.createConsumptionChangeLog(
                ConsumptionChangeLogSaveReqVO.builder()
                        .userId(recipientIntegral.getUserId())
                        .consumptionPoints(createReqVO.getConsumptionPoints())
                        .afterConsumptionPoints(recipientIntegral.getConsumptionPoints())
                        .consumptionStatus(ConsumptionEnum.CONSUMPTION_RECIPIENT.getType())
                        .generateUserId(transferIntegral.getUserId())
                        .build()
        );

        // 插入
        ConsumptionTransferLogDO consumptionTransferLog = BeanUtils.toBean(createReqVO, ConsumptionTransferLogDO.class);
        consumptionTransferLog.setConsumptionPoints(-consumptionTransferLog.getConsumptionPoints());
        consumptionTransferLog.setRecipientPoints(-consumptionTransferLog.getConsumptionPoints());
        consumptionTransferLog.setAfterTransferConsumptionPoints(transferIntegral.getConsumptionPoints());
        consumptionTransferLog.setAfterRecipientConsumptionPoints(recipientIntegral.getConsumptionPoints());
        consumptionTransferLogMapper.insert(consumptionTransferLog);

        // 发送短信到接收者
        MemberUserDO receiverUser = memberUserService.getUser(createReqVO.getRecipientUserId());
        smsCodeService.sendSmsCode(new SmsCodeSendReqDTO()
                .setMobile(receiverUser.getMobile())
                .setScene(SmsSceneEnum.CONSUMPTION_POINTS_TRANSFER_INFORM.getScene())
                .setCreateIp(getClientIP())
                .setName(user.getUsername())
                .setMoney(createReqVO.getConsumptionPoints() / DistriConstants.INTEGRAL_PAGE2DB));
        // 返回
        return consumptionTransferLog.getId();
    }

    @Override
    public void updateConsumptionTransferLog(ConsumptionTransferLogSaveReqVO updateReqVO) {
        // 校验存在
        validateConsumptionTransferLogExists(updateReqVO.getId());
        // 更新
        ConsumptionTransferLogDO updateObj = BeanUtils.toBean(updateReqVO, ConsumptionTransferLogDO.class);
        consumptionTransferLogMapper.updateById(updateObj);
    }

    @Override
    public void deleteConsumptionTransferLog(Long id) {
        // 校验存在
        validateConsumptionTransferLogExists(id);
        // 删除
        consumptionTransferLogMapper.deleteById(id);
    }

    private void validateConsumptionTransferLogExists(Long id) {
        if (consumptionTransferLogMapper.selectById(id) == null) {
            throw exception(CONSUMPTION_TRANSFER_LOG_NOT_EXISTS);
        }
    }

    @Override
    public ConsumptionTransferLogDO getConsumptionTransferLog(Long id) {
        return consumptionTransferLogMapper.selectById(id);
    }

    @Override
    public PageResult<ConsumptionTransferLogDO> getConsumptionTransferLogPage(ConsumptionTransferLogPageReqVO pageReqVO) {
        pageReqVO.setTransferUserId(getLoginUserId());
        return consumptionTransferLogMapper.selectPage(pageReqVO);
    }

}