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

import cn.newfeifan.mall.framework.common.exception.ErrorCode;
import cn.newfeifan.mall.module.distri.constant.DistriConstants;
import cn.newfeifan.mall.module.distri.controller.admin.integral.vo.IntegralSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.app.applicationforwithdrawalchannel.vo.AppApplicationForWithdrawalChannelSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.app.ptdailywithdrawal.vo.AppPtDailyWithdrawalSaveReqVO;
import cn.newfeifan.mall.module.distri.controller.app.ptprofitlog.vo.PtProfitLogSaveReqVO;
import cn.newfeifan.mall.module.distri.dal.dataobject.applicationforwithdrawalchannel.ApplicationForWithdrawalChannelDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.integral.IntegralDO;
import cn.newfeifan.mall.module.distri.dal.dataobject.ptdailywithdrawal.PtDailyWithdrawalDO;
import cn.newfeifan.mall.module.distri.enums.CaclEnum;
import cn.newfeifan.mall.module.distri.enums.WithdrawalChannelTypeEnum;
import cn.newfeifan.mall.module.distri.service.applicationforwithdrawalchannel.ApplicationForWithdrawalChannelService;
import cn.newfeifan.mall.module.distri.service.integral.IntegralService;
import cn.newfeifan.mall.module.distri.service.ptdailywithdrawal.PtDailyWithdrawalService;
import cn.newfeifan.mall.module.distri.service.ptprofitlog.PtProfitLogService;
import cn.newfeifan.mall.module.member.dal.dataobject.user.MemberUserDO;
import cn.newfeifan.mall.module.member.service.user.MemberUserService;
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.app.applicationforwithdrawal.vo.*;
import cn.newfeifan.mall.module.distri.dal.dataobject.applicationforwithdrawal.ApplicationForWithdrawalDO;
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.applicationforwithdrawal.ApplicationForWithdrawalMapper;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
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 ApplicationForWithdrawalServiceImpl implements ApplicationForWithdrawalService {

    @Resource
    private ApplicationForWithdrawalMapper applicationForWithdrawalMapper;

    @Resource
    private ApplicationForWithdrawalChannelService applicationForWithdrawalChannelService;

    @Resource
    private PtDailyWithdrawalService ptDailyWithdrawalService;

    @Resource
    private MemberUserService userService;

    @Resource
    private IntegralService integralService;

    @Resource
    private PtProfitLogService ptProfitLogService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createApplicationForWithdrawal(AppApplicationForWithdrawalSaveReqVO reqVO) {

        // 获取用户钱包
        IntegralDO integralDO = integralService.selectByUser(getLoginUserId());

        if(integralDO.getCurrentQuota() < reqVO.getAmount() * DistriConstants.INTEGRAL_PAGE2DB){
            ErrorCode ERROR = new ErrorCode(1_005_031_005, "积分不足!");
            throw exception(ERROR);
        }

        // 获取pt一级提现记录
        PtDailyWithdrawalDO ptDailyWithdrawalDO = ptDailyWithdrawalService.getPtDailyWithdrawalToDay();

        // 二级提现记录
        ApplicationForWithdrawalChannelDO applicationForWithdrawalChannelDO = applicationForWithdrawalChannelService.getApplicationForWithdrawalChannel(reqVO.getWithdrawalType(), ptDailyWithdrawalDO.getId());

        // 插入
        MemberUserDO user = userService.getUser(getLoginUserId());

        reqVO.setApplicationForWithdrawalChannelId(applicationForWithdrawalChannelDO.getId());
        reqVO.setUserId(user.getId());

        // 根据渠道获取对应账号
        if (reqVO.getWithdrawalType().equals(WithdrawalChannelTypeEnum.ALIPAY.getType())) {
            reqVO.setWithdrawalAccount(user.getAlipayAccount());
        } else if (reqVO.getWithdrawalType().equals(WithdrawalChannelTypeEnum.BANK.getType())) {
            reqVO.setWithdrawalAccount(user.getBankAccount());
        }

        if(reqVO.getWithdrawalAccount() == null || reqVO.getWithdrawalAccount().isEmpty()){
            ErrorCode ERROR = new ErrorCode(1_005_031_005, "提现账号不能为空!");
            throw exception(ERROR);
        }

        ApplicationForWithdrawalDO applicationForWithdrawal = BeanUtils.toBean(reqVO, ApplicationForWithdrawalDO.class);
        applicationForWithdrawalMapper.insert(applicationForWithdrawal);

        // 每一次申请就会改变二级表总数据
        applicationForWithdrawalChannelDO.setAmount(applicationForWithdrawalChannelDO.getAmount() + reqVO.getAmount());
        applicationForWithdrawalChannelDO.setCount(applicationForWithdrawalChannelDO.getCount() + 1);
        applicationForWithdrawalChannelService.updateApplicationForWithdrawalChannel(BeanUtils.toBean(applicationForWithdrawalChannelDO, AppApplicationForWithdrawalChannelSaveReqVO.class));

        // 每一次申请就会改变一级表总数据
        ptDailyWithdrawalDO.setAmount(ptDailyWithdrawalDO.getAmount() + reqVO.getAmount());
        ptDailyWithdrawalDO.setCount(ptDailyWithdrawalDO.getCount() + 1);
        ptDailyWithdrawalService.updatePtDailyWithdrawal(BeanUtils.toBean(ptDailyWithdrawalDO, AppPtDailyWithdrawalSaveReqVO.class));

        // 修改用户钱包余额
        integralDO.setCurrentQuota(integralDO.getCurrentQuota() - reqVO.getAmount() * DistriConstants.INTEGRAL_PAGE2DB);
        integralService.updateIntegral(BeanUtils.toBean(integralDO, IntegralSaveReqVO.class));

        // 记录用户积分变动日志
        PtProfitLogSaveReqVO ptProfitLogSaveReqVO = PtProfitLogSaveReqVO.builder()
                .amount(-reqVO.getAmount() * DistriConstants.INTEGRAL_PAGE2DB)
                .afterAmount(integralDO.getCurrentQuota())
                .profitStatus(CaclEnum.WITHDRAWAL.getType())
                .userId(user.getId())
                .generateUserId(user.getId())
                .build();
        ptProfitLogService.createPtProfitLog(ptProfitLogSaveReqVO);

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

    @Override
    public void updateApplicationForWithdrawal(AppApplicationForWithdrawalSaveReqVO updateReqVO) {
        // 校验存在
        validateApplicationForWithdrawalExists(updateReqVO.getId());
        // 更新
        ApplicationForWithdrawalDO updateObj = BeanUtils.toBean(updateReqVO, ApplicationForWithdrawalDO.class);
        applicationForWithdrawalMapper.updateById(updateObj);
    }

    @Override
    public void deleteApplicationForWithdrawal(Long id) {
        // 校验存在
        validateApplicationForWithdrawalExists(id);
        // 删除
        applicationForWithdrawalMapper.deleteById(id);
    }

    private void validateApplicationForWithdrawalExists(Long id) {
        if (applicationForWithdrawalMapper.selectById(id) == null) {
            throw exception(APPLICATION_FOR_WITHDRAWAL_NOT_EXISTS);
        }
    }

    @Override
    public ApplicationForWithdrawalDO getApplicationForWithdrawal(Long id) {
        return applicationForWithdrawalMapper.selectById(id);
    }

    @Override
    public PageResult<ApplicationForWithdrawalDO> getApplicationForWithdrawalPage(AppApplicationForWithdrawalPageReqVO pageReqVO) {

        pageReqVO.setUserId(getLoginUserId());

        PageResult<ApplicationForWithdrawalDO> result = applicationForWithdrawalMapper.selectPage(pageReqVO);

        for (ApplicationForWithdrawalDO withdrawalDO : result.getList()) {
            withdrawalDO.setWithdrawalAccount(formatAccount(withdrawalDO.getWithdrawalAccount()));
        }

        return result;
    }

    /**
     * 格式化账号，只显示前三位和后四位，中间用*代替
     *
     * @param account 原始账号字符串
     * @return 格式化后的账号
     */
    private String formatAccount(String account) {
        if (account == null || account.length() <= 7) {
            return "****"; // 如果账号长度小于等于7，显示四个星号
        }

        // 截取前三位
        String firstPart = account.substring(0, 3);
        // 截取后四位
        String lastPart = account.substring(account.length() - 4);

        // 生成中间的*部分
        String middlePart = "****";

        // 拼接最终的格式化账号
        return firstPart + middlePart + lastPart;
    }

}