package com.ruoyi.ss.withdraw.service.impl;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ss.changeBalance.service.IChangeBalanceService;
import com.ruoyi.ss.transfer.domain.TransferVO;
import com.ruoyi.ss.transfer.interfaces.AfterTransfer;
import com.ruoyi.ss.transfer.service.TransferConverter;
import com.ruoyi.ss.transfer.service.TransferService;
import com.ruoyi.ss.withdraw.domain.Withdraw;
import com.ruoyi.ss.withdraw.domain.WithdrawQuery;
import com.ruoyi.ss.withdraw.domain.WithdrawVO;
import com.ruoyi.ss.withdraw.domain.dto.WithdrawApprovalDTO;
import com.ruoyi.ss.withdraw.mapper.WithdrawMapper;
import com.ruoyi.ss.withdraw.service.IWithdrawService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

import static com.ruoyi.common.constant.ServiceConstants.*;

/**
 * 提现记录Service业务层处理
 *
 * @author qzz
 * @date 2024-09-28
 */
@Service
public class WithdrawServiceImpl implements IWithdrawService, AfterTransfer
{
    @Autowired
    private WithdrawMapper withdrawMapper;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private TransferService transferService;

    @Autowired
    private TransferConverter transferConverter;

    @Autowired
    private IChangeBalanceService changeBalanceService;


    /**
     * 查询提现记录
     *
     * @param id 提现记录主键
     * @return 提现记录
     */
    @Override
    public WithdrawVO selectRlWithdrawById(Long id)
    {
        return withdrawMapper.selectRlWithdrawById(id);
    }

    /**
     * 查询提现记录列表
     *
     * @param rlWithdraw 提现记录
     * @return 提现记录
     */
    @Override
    @DataScope(merchantAlias = "u")
    public List<Withdraw> selectRlWithdrawList(WithdrawQuery rlWithdraw)
    {
        return withdrawMapper.selectRlWithdrawList(rlWithdraw);
    }

    @Override
    public int selectCount(WithdrawQuery rlWithdraw) {
        return withdrawMapper.selectCount(rlWithdraw);
    }

    /**
     * 新增提现记录
     *
     * @param rlWithdraw 提现记录
     * @return 结果
     */
    @Override
    public int insertRlWithdraw(Withdraw rlWithdraw)
    {
        rlWithdraw.setCreateTime(DateUtils.getNowDate());
        return withdrawMapper.insertRlWithdraw(rlWithdraw);
    }

    /**
     * 修改提现记录
     *
     * @param rlWithdraw 提现记录
     * @return 结果
     */
    @Override
    public int updateRlWithdraw(Withdraw rlWithdraw)
    {
        return withdrawMapper.updateRlWithdraw(rlWithdraw);
    }

    /**
     * 批量删除提现记录
     *
     * @param ids 需要删除的提现记录主键
     * @return 结果
     */
    @Override
    public int deleteRlWithdrawByIds(Long[] ids)
    {
        return withdrawMapper.deleteRlWithdrawByIds(ids);
    }

    /**
     * 删除提现记录信息
     *
     * @param id 提现记录主键
     * @return 结果
     */
    @Override
    public int deleteRlWithdrawById(Long id)
    {
        return withdrawMapper.deleteRlWithdrawById(id);
    }

    /**
     * 累计提现金额
     *
     * @param RlUserId 用户id
     * @return 结果
     */
    @Override
    public BigDecimal cumulativeWithdrawalAmount(Long RlUserId) {
        return withdrawMapper.cumulativeWithdrawalAmount(RlUserId);
    }

    /**
     * 同意提现
     *
     * @param dto 提现审核DTO
     * @return 结果
     */
    @Override
    public int passWithdraw(WithdrawApprovalDTO dto) {
        ServiceUtil.assertion(StrUtil.isBlank(dto.getWithdrawNo()), "提现申请ID不允许为空");
        String lockKey = dto.getWithdrawNo();
        ServiceUtil.assertion(!redisLock.lock(RedisLockKey.APPROVAL_WITHDRAW, lockKey), "该提现申请正在审核，请刷新后重试");
        try {
                int update = 0;
                WithdrawVO withdrawVO = withdrawMapper.selectRlWithdrawByWithdrawNo(dto.getWithdrawNo());
                ServiceUtil.assertion(withdrawVO == null, "提现申请单不存在");
                ServiceUtil.assertion(!WITHDRAW_STATUS_APPLY.equals(withdrawVO.getStatus()), "提现申请单状态异常");

                Integer result = transactionTemplate.execute(status -> {
                    Withdraw updateWithdraw =  new Withdraw();
                    updateWithdraw.setId(withdrawVO.getId());
                    if(WITHDRAW_TYPE_ONLINE.equals(withdrawVO.getType()) && withdrawVO.getIsAuto()){//线上打款并且自动打款，状态是打款中
                        updateWithdraw.setStatus(WITHDRAW_STATUS_IN_PAYMENT);
                    }else{
                        updateWithdraw.setStatus(WITHDRAW_STATUS_PASS);
                    }
                    updateWithdraw.setAuditTime(LocalDateTime.now());
                    updateWithdraw.setRejectReason(dto.getRejectReason());
                    int i = withdrawMapper.updateRlWithdraw(updateWithdraw);
                    ServiceUtil.assertion(i != 1, "更新提现状态失败，请刷新后重试");

                    // 线上打款，发起打款
                    if (WITHDRAW_TYPE_ONLINE.equals(withdrawVO.getType()) && withdrawVO.getIsAuto()) {
                        boolean pay = this.startPayOnline(withdrawVO);
                        ServiceUtil.assertion(!pay, "发起打款失败");
                    }

                    return update;
                });

            return result == null ? 0 : result;
        } finally {
            redisLock.unlock(RedisLockKey.APPROVAL_WITHDRAW, lockKey);
        }
    }

    /**
     * 提现线上打款
     */
    private boolean startPayOnline(WithdrawVO withdraw) {
        ServiceUtil.assertion(WITHDRAW_STATUS_PASS.equals(withdraw.getStatus()), "当前提现单据状态异常");
        ServiceUtil.assertion(StringUtils.isBlank(withdraw.getWxOpenid()), "提现单openid不存在");

        // 生成转账单
        TransferVO vo = transferConverter.toVo(withdraw);

        Boolean result = transactionTemplate.execute(status -> {
            // 插入数据
            int insert = transferService.insertWithDetail(vo);
            ServiceUtil.assertion(insert != 1, "新增转账单失败");

            // 发起转账
            boolean requestResult = transferService.requestTransfer(vo.getBatchNo());
            ServiceUtil.assertion(!requestResult, "发起转账失败");

            return true;
        });
        return result != null && result;
    }

    /**
     * 拒绝提现
     *
     * @param dto 提现审核DTO
     * @return 结果
     */
    @Override
    public boolean rejectWithdraw(WithdrawApprovalDTO dto) {
        ServiceUtil.assertion(StrUtil.isBlank(dto.getWithdrawNo()), "提现申请ID不允许为空");
        String lockKey = dto.getWithdrawNo();
        ServiceUtil.assertion(!redisLock.lock(RedisLockKey.APPROVAL_WITHDRAW, lockKey), "该提现申请正在审核，请刷新后重试");
        try {
            WithdrawVO withdrawVO = withdrawMapper.selectRlWithdrawByWithdrawNo(dto.getWithdrawNo());
            ServiceUtil.assertion(withdrawVO == null, "提现申请单不存在");
            ServiceUtil.assertion(!WITHDRAW_STATUS_APPLY.equals(withdrawVO.getStatus()), "提现申请单状态异常");

            transactionTemplate.execute(status -> {
                // 审核 更新提现状态
                Withdraw updateWithdraw =  new Withdraw();
                updateWithdraw.setId(withdrawVO.getId());
                updateWithdraw.setStatus(WITHDRAW_STATUS_REJECT);
                updateWithdraw.setRejectReason(dto.getRejectReason());
                updateWithdraw.setAuditTime(LocalDateTime.now());
                updateWithdraw.setRejectReason(dto.getRejectReason());
                int i1 = withdrawMapper.updateRlWithdraw(updateWithdraw);
                ServiceUtil.assertion(i1 != 1, "更新提现状态失败，请刷新后重试");

                // 返还客户余额
                int i2 = changeBalanceService.generateChangeBalance(dto.getWithdrawNo(), null, ServiceConstants.FLOW_TYPE_INCOME,
                        ServiceConstants.WITHDRAWAL_FAILED, withdrawVO.getAmount(), withdrawVO.getOwnerId(), withdrawVO.getUserName(), withdrawVO.getOwnerPhone(),withdrawVO.getOwnerType());
                ServiceUtil.assertion(i2 != 1, "拒绝提现，返还客户余额失败");
                return i2;
            });

            return true;
        } finally {
            redisLock.unlock(RedisLockKey.APPROVAL_WITHDRAW, lockKey);
        }
    }

    /**
     * 获取用户提现中金额
     *
     * @param userId 用户id
     * @return 结果
     */
    @Override
    public BigDecimal selectWithdrawingAmountByUserId(Long userId) {
        return withdrawMapper.selectWithdrawingAmountByUserId(userId);
    }

    /**
     * 根据条件查询提现金额
     *
     * @param query 查询条件
     * @return 结果
     */
    @Override
    public BigDecimal selectWithdrawAmount(WithdrawQuery query) {
        return withdrawMapper.selectWithdrawAmount(query);
    }

    /**
     * 根据条件查询提现服务费
     *
     * @param query 查询条件
     * @return 结果
     */
    @Override
    public BigDecimal selectHandlingCharge(WithdrawQuery query) {
        return withdrawMapper.selectHandlingCharge(query);
    }


    @Override
    public int onTransferSuccess(TransferVO transfer) {
        if (transfer == null || transfer.getBstId() == null) {
            return 0;
        }
        WithdrawVO withdraw = this.selectRlWithdrawById(transfer.getBstId());
        ServiceUtil.assertion(!withdraw.getStatus().equals(WITHDRAW_STATUS_IN_PAYMENT), "提现状态已发生改变");

        Integer result = transactionTemplate.execute(status -> {
            // 修改提现状态
            Withdraw data = new Withdraw();
            data.setStatus(WITHDRAW_STATUS_PAID);
            data.setId(transfer.getBstId());
            int update = updateRlWithdraw(data);
            ServiceUtil.assertion(update != 1, "修改提现状态失败，提现状态已发生改变");
            return update;
        });

        return result == null ? 0 : result;
    }

    @Override
    public int onTransferFail(TransferVO transfer) {
        if (transfer == null || transfer.getBstId() == null) {
            return 0;
        }

        WithdrawVO withdraw = this.selectRlWithdrawById(transfer.getBstId());
        ServiceUtil.assertion(!withdraw.getStatus().equals(WITHDRAW_STATUS_IN_PAYMENT), "提现状态已发生改变");

        Integer result = transactionTemplate.execute(status -> {
            // 修改提现状态
            Withdraw data = new Withdraw();
            data.setStatus(FLOW_STATUS_FAIL);
            data.setId(transfer.getBstId());
            int update = updateRlWithdraw(data);
            ServiceUtil.assertion(update != 1, "修改提现状态失败，提现状态已发生改变");

            // 返还客户余额
            int i2 = changeBalanceService.generateChangeBalance(withdraw.getWithdrawNo(), null, ServiceConstants.FLOW_TYPE_INCOME,
                    ServiceConstants.WITHDRAWAL_FAILED, withdraw.getAmount(), withdraw.getOwnerId(), withdraw.getUserName(), withdraw.getOwnerPhone(),withdraw.getOwnerType());
            ServiceUtil.assertion(i2 != 1, "转账失败，返还客户余额失败");
            return update;
        });

        return result == null ? 0 : result;
    }
}
