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

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

import com.ruoyi.bst.account.domain.AccountVO;
import com.ruoyi.bst.account.domain.enums.AccountType;
import com.ruoyi.bst.account.service.AccountService;
import com.ruoyi.bst.balanceLog.domain.enums.BalanceLogBstType;
import com.ruoyi.bst.withdraw.domain.dto.WithdrawVerifyDTO;
import com.ruoyi.bst.withdraw.domain.enums.WithdrawStatus;
import com.ruoyi.bst.withdraw.domain.vo.WithdrawAmountVO;
import com.ruoyi.bst.withdraw.service.WithdrawConverter;
import com.ruoyi.bst.withdraw.utils.WithdrawUtil;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MathUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.SnowFlakeUtil;
import com.ruoyi.system.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.bst.withdraw.mapper.WithdrawMapper;
import com.ruoyi.bst.withdraw.domain.Withdraw;
import com.ruoyi.bst.withdraw.domain.WithdrawVO;
import com.ruoyi.bst.withdraw.domain.WithdrawQuery;
import com.ruoyi.bst.withdraw.service.WithdrawService;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 提现Service业务层处理
 *
 * @author ruoyi
 * @date 2025-04-07
 */
@Service
public class WithdrawServiceImpl implements WithdrawService
{
    @Autowired
    private WithdrawMapper withdrawMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private WithdrawConverter withdrawConverter;

    @Autowired
    private AccountService accountService;
    @Autowired
    private TransactionTemplate transactionTemplate;

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

    /**
     * 查询提现列表
     *
     * @param withdraw 提现
     * @return 提现
     */
    @Override
    public List<WithdrawVO> selectWithdrawList(WithdrawQuery withdraw)
    {
        return withdrawMapper.selectWithdrawList(withdraw);
    }

    /**
     * 新增提现
     *
     * @param withdraw 提现
     * @return 结果
     */
    @Override
    public int insertWithdraw(Withdraw withdraw) {
        // 获取用户信息
        UserVO user = userService.selectUserById(withdraw.getUserId());
        ServiceUtil.assertion(user == null, "ID为%s的用户不存在", withdraw.getUserId());
        // 获取账户信息
        AccountVO account = accountService.selectAccountById(withdraw.getAccountId());
        ServiceUtil.assertion(account == null, "ID为%s的收款账户不存在", withdraw.getAccountId());

        // 获取金额
        WithdrawAmountVO amountVo = withdrawConverter.calcAmount(user, withdraw.getAmount());
        ServiceUtil.assertion(amountVo == null, "计算金额出错");
        // 校验金额
        ServiceUtil.assertion(!MathUtils.equals(amountVo.getServiceCharge(), withdraw.getServiceCharge()), "服务费金额发生变化，请刷新后重试");
        ServiceUtil.assertion(!MathUtils.equals(amountVo.getAmount(), withdraw.getArrivalAmount()), "到账金额发生变化，请刷新后重试");
        ServiceUtil.assertion(MathUtils.smallerThan(withdraw.getAmount(), amountVo.getMinAmount()), "提现金额不允许小于最低金额：%s", amountVo.getMinAmount());
        ServiceUtil.assertion(MathUtils.biggerThan(withdraw.getAmount(), amountVo.getMaxAmount()), "提现金额不允许大于最高金额：%s", amountVo.getMaxAmount());

        // 组装提现数据
        Withdraw data = new Withdraw();
        // 基础
        data.setUserId(withdraw.getUserId());
        data.setCreateTime(DateUtils.getNowDate());
        data.setNo(String.valueOf(SnowFlakeUtil.newId()));
        data.setStatus(WithdrawStatus.WAIT_VERIFY.getCode());
        // 账户
        data.setAccountId(withdraw.getAccountId());
        data.setAccountType(account.getType());
        data.setAccountNo(account.getNo());
        data.setAccountName(account.getName());
        data.setAccountMobile(account.getMobile());
        data.setAccountIdCard(account.getIdCard());
        data.setBankName(account.getBankName());
        data.setBankCardName(account.getBankCardName());
        data.setBankType(account.getBankType());
        // 金额
        data.setServiceType(amountVo.getType());
        data.setServiceCharge(amountVo.getServiceCharge());
        data.setServicePoint(amountVo.getPoint());
        data.setAmount(withdraw.getAmount());
        data.setArrivalAmount(amountVo.getAmount());
        Integer result = transactionTemplate.execute(status -> {
            int rows = withdrawMapper.insertWithdraw(data);

            if (rows > 0) {
                // 扣减用户余额
                int sub = userService.subtractBalance(data.getUserId(), data.getAmount(), BalanceLogBstType.WITHDRAW, data.getId(), "提现申请:" + data.getNo(), true);
                ServiceUtil.assertion(sub != 1, "扣减用户余额失败，请检查余额是否充足");
            }

            return rows;
        });

        return result == null ? 0 : result;
    }

    /**
     * 修改提现
     *
     * @param withdraw 提现
     * @return 结果
     */
    @Override
    public int updateWithdraw(Withdraw withdraw)
    {
        return withdrawMapper.updateWithdraw(withdraw);
    }

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

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

    @Override
    public int verify(WithdrawVerifyDTO dto) {
        WithdrawVO withdraw = selectWithdrawById(dto.getId());
        ServiceUtil.assertion(withdraw == null, "待审核的提现不存在");
        ServiceUtil.assertion(!WithdrawStatus.canVerify().contains(withdraw.getStatus()), "ID为%s的提现当前状态不允许审核", dto.getId());

        boolean pass = dto.getPass() != null && dto.getPass();

        Integer result = transactionTemplate.execute(status -> {
            Withdraw data = new Withdraw();
            if (pass) {
                if (AccountType.offline().contains(withdraw.getAccountType())) {
                    data.setStatus(WithdrawStatus.SUCCESS.getCode());
                } else {
                    data.setStatus(WithdrawStatus.PAYING.getCode());
                }
            } else {
                data.setStatus(WithdrawStatus.REJECTED.getCode());
            }
            data.setVerifyUserId(dto.getVerifyId());
            data.setVerifyTime(LocalDateTime.now());
            data.setVerifyRemark(dto.getRemark());
            WithdrawQuery query = new WithdrawQuery();
            query.setId(dto.getId());
            query.setStatusList(WithdrawStatus.canVerify());
            int rows = withdrawMapper.updateByQuery(data, query);

            if (rows > 0 ) {
                if (WithdrawStatus.PAYING.getCode().equals(data.getStatus())) {
                    // TODO 支付中，线上提现打款
                    throw new ServiceException("暂未开通线上提现打款");
                } else if (WithdrawStatus.REJECTED.getCode().equals(data.getStatus())) {
                    // 驳回，恢复用户余额
                    int add = userService.addBalance(
                            withdraw.getUserId(),
                            withdraw.getAmount(),
                            BalanceLogBstType.WITHDRAW,
                            withdraw.getId(),
                            "提现驳回：" + withdraw.getNo()
                    );
                    ServiceUtil.assertion(add != 1, "恢复用户余额失败");
                }
            }

            return rows;
        });

        return result == null ? 0 : result;
    }

}
