package com.kxs.user.biz.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kxs.common.core.constant.CommonConstants;
import com.kxs.common.core.util.R;
import com.kxs.common.security.util.SecurityUtils;
import com.kxs.user.api.dto.kxsapp.userAccount.WithdrawDepositDTO;
import com.kxs.user.api.model.KxsUserAmount;
import com.kxs.user.api.model.KxsUserBank;
import com.kxs.user.api.vo.kxsapp.userAccount.WithdrawDetailVO;
import com.kxs.user.api.vo.kxsapp.userAccount.WithdrawListVO;
import com.kxs.user.biz.constant.enums.UserErrorTypeEnum;
import com.kxs.user.biz.constant.enums.WithdrawalStatusEnum;
import com.kxs.user.biz.mapper.KxsUserAmountMapper;
import com.kxs.user.biz.mapper.KxsUserBankMapper;
import com.kxs.user.biz.mapper.KxsUserWithdrawalMapper;
import com.kxs.user.api.model.KxsUserWithdrawal;
import com.kxs.user.biz.service.KxsUserService;
import com.kxs.user.biz.service.KxsUserWithdrawalService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * 用户提现申请表(KxsUserWithdrawal)表服务实现类
 *
 * @author 系统
 * @since 2024-01-03 09:39:56
 */
@Service("kxsUserWithdrawalService")
@RequiredArgsConstructor
public class KxsUserWithdrawalServiceImpl extends ServiceImpl<KxsUserWithdrawalMapper, KxsUserWithdrawal> implements KxsUserWithdrawalService {

    private final KxsUserService kxsUserService;

    private final KxsUserBankMapper userBankMapper;

    private final KxsUserAmountMapper userAmountMapper;

    /**
     * 税费比例
     */
    private static final double TXT_RATIO = 0.08;

    /**
     * 服务费不满500 扣除3元每笔
     */
    private static final int SERVICE_CHARGE = 2;

    /**
     * 最大提现金额
     */
    private static final BigDecimal MAX_AMOUNT = new BigDecimal("50000");

    /**
     * 提现阈值
     */
    private static final BigDecimal SERVICE_AMOUNT = new BigDecimal("100");

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R withdrawDeposit(WithdrawDepositDTO param) {

        Long userId = SecurityUtils.getUser().getId();

        if (!kxsUserService.checkPayPwd(param.getPayPwd())) {
            return R.failed(UserErrorTypeEnum.PWD_ERROR.getDescription());
        }

        //超限
        if(param.getApplyAmount().compareTo(MAX_AMOUNT) > 0){
            return R.failed(UserErrorTypeEnum.WITHDRAW_MAX.getDescription());
        }

        //查询银行卡
        KxsUserBank userBank = userBankMapper.selectOne(Wrappers.<KxsUserBank>lambdaQuery().eq(KxsUserBank::getUserId, userId));
        if(userBank == null){
            return R.failed(UserErrorTypeEnum.NOT_REAL.getDescription());
        }

        //查询余额
        KxsUserAmount userAmount = userAmountMapper.selectOne(Wrappers.<KxsUserAmount>lambdaQuery().eq(KxsUserAmount::getUserId, userId).last("FOR UPDATE"));
        //余额减去预扣款金额
        BigDecimal amount = NumberUtil.sub(userAmount.getAmount(), userAmount.getAdvanceAmount());
        //验证余额
        if (amount.compareTo(param.getApplyAmount()) < 0) {
            return R.failed(UserErrorTypeEnum.NOT_SUFFICIENT_FUNDS.getDescription());
        }

        //订单号
        String orderSn = CommonConstants.KXS_WITHDRAWAL_PREFIX + IdUtil.getSnowflakeNextIdStr();

        KxsUserWithdrawal kxsUserWithdrawal = new KxsUserWithdrawal();
        kxsUserWithdrawal.setUserId(userId.intValue());
        kxsUserWithdrawal.setApplyNo(orderSn);
        kxsUserWithdrawal.setBankCode(userBank.getBankCode());
        kxsUserWithdrawal.setBankName(userBank.getBankName());
        kxsUserWithdrawal.setApplyAmount(param.getApplyAmount());

        //计算税费
        BigDecimal taxAmount = NumberUtil.mul(param.getApplyAmount(), TXT_RATIO);
        kxsUserWithdrawal.setTaxAmount(taxAmount);

        //服务费
        BigDecimal serviceCharge = BigDecimal.ZERO;
        if(param.getApplyAmount().compareTo(SERVICE_AMOUNT) <= 0) {
            serviceCharge = BigDecimal.valueOf(SERVICE_CHARGE);
        }
        kxsUserWithdrawal.setServiceAmount(serviceCharge);

        //实际到账-税费-服务费
        kxsUserWithdrawal.setRealAmount(NumberUtil.sub(param.getApplyAmount(), taxAmount, serviceCharge));
        baseMapper.insert(kxsUserWithdrawal);

        //扣除可使用金额到冻结金额
        //可用余额减少
        userAmount.setAmount(NumberUtil.sub(userAmount.getAmount(), param.getApplyAmount()));
        //冻结金额相加
        userAmount.setFrozenAmount(NumberUtil.add(userAmount.getFrozenAmount(), param.getApplyAmount()));
        userAmountMapper.updateById(userAmount);

        return R.ok();
    }

    @Override
    public IPage<WithdrawListVO> withdrawListPage(Page<WithdrawListVO> page) {
        IPage<WithdrawListVO> byPage = baseMapper.getByPage(page);

        for (WithdrawListVO record : byPage.getRecords()) {
            String statusNo = EnumUtil.getFieldBy(WithdrawalStatusEnum::getDescription, WithdrawalStatusEnum::getType, record.getStatus());
            record.setStatusNo(statusNo);
            //隐藏卡号
            String bankCode = CharSequenceUtil.subBetween(record.getTitle(), "(", ")");
            String bankCodeFour = bankCode.substring(bankCode.length() - 4);
            String bankName = CharSequenceUtil.subBefore(record.getTitle(), "(", false);
            record.setTitle(bankName + "(" +bankCodeFour + ")");
        }
        return byPage;
    }

    @Override
    public WithdrawDetailVO withdrawDetail(Integer id) {

        KxsUserWithdrawal kxsUserWithdrawal = baseMapper.selectById(id);

        WithdrawDetailVO detailVO = new WithdrawDetailVO();

        BeanUtils.copyProperties(kxsUserWithdrawal, detailVO);

        String statusNo = EnumUtil.getFieldBy(WithdrawalStatusEnum::getDescription, WithdrawalStatusEnum::getType, kxsUserWithdrawal.getStatus());
        detailVO.setStatusNo(statusNo);

        return detailVO;
    }
















}

