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

import com.ruoyi.common.core.domain.BaseValidator;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.ServiceCode;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.risk.domain.RiskQuery;
import com.ruoyi.ss.risk.domain.RiskVO;
import com.ruoyi.ss.risk.domain.enums.RiskType;
import com.ruoyi.ss.risk.service.RiskService;
import com.ruoyi.ss.transactionBill.domain.TransactionBillQuery;
import com.ruoyi.ss.transactionBill.domain.bo.WithdrawBO;
import com.ruoyi.ss.transactionBill.domain.dto.WithdrawDTO;
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillStatus;
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillType;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
import com.ruoyi.ss.transactionBill.service.WithdrawValidator;
import com.ruoyi.ss.user.domain.SmUserVO;
import com.ruoyi.system.domain.enums.config.ConfigKey;
import com.ruoyi.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @author wjh
 * 2024/9/21
 */
@Service
public class WithdrawValidatorImpl extends BaseValidator implements WithdrawValidator {

    @Autowired
    private TransactionBillService transactionBillService;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private RiskService riskService;

    @Autowired
    private RedisCache redisCache;

    /**
     * 判断提现是否有风险
     *
     * @param bo
     */
    @Override
    public boolean hasRisk(WithdrawBO bo) {
        if (bo == null || bo.getUser() == null || bo.getDto() == null) {
            return false;
        }
        SmUserVO user = bo.getUser();
        WithdrawDTO dto = bo.getDto();

        // 查询时间相近的充值订单
        int riskWithdrawTime = sysConfigService.getInt(ConfigKey.RISK_WITHDRAW_TIME); // 最低允许相隔时长（分钟）
        TransactionBillQuery query = new TransactionBillQuery();
        query.setUserId(user.getUserId());
        query.setType(TransactionBillType.RECHARGE.getType());
        query.setStatus(TransactionBillStatus.SUCCESS.getStatus());
        query.setCreateTimeStart(LocalDateTime.now().plusMinutes(-riskWithdrawTime));
        List<TransactionBillVO> list = transactionBillService.selectSmTransactionBillList(query);

        // 计算总金额
        BigDecimal rechargeAmount = list.stream().map(TransactionBillVO::getArrivalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (rechargeAmount.compareTo(BigDecimal.ZERO) == 0) {
            return false;
        }

        // 判断订单金额是否和提现一致，若一致则判定为风险
        // FIXME 可以考虑使用一个范围，在这个误差范围内，均为风险
        return dto.getMoney() != null && rechargeAmount.compareTo(dto.getMoney()) == 0;
    }

    @Override
    public void checkWithdrawRisk(SmUserVO user) {
        if (user == null || user.getUserId() == null) {
            return;
        }

        // 查询未结束的风控列表
        RiskQuery query = new RiskQuery();
        query.setUserId(user.getUserId());
        query.setContainsType(RiskType.WITHDRAW.getType());
        List<RiskVO> riskList = riskService.selectNotFinishedList(query);

        if (CollectionUtils.isNotEmptyElement(riskList)) {
            RiskVO risk = riskList.get(0);
            ServiceUtil.assertion(risk == null, "风控信息异常");
            LocalDateTime endTime = risk.getEndTime();
            if (endTime == null) {
                throw new ServiceException("您被限制提现：" +  risk.getReason(),
                        ServiceCode.RISK_WITHDRAW.getCode(),
                        risk.getRiskId()
                );
            } else if (endTime.isAfter(LocalDateTime.now())){
                throw new ServiceException("您被限制提现至" + DateUtils.format(endTime, DateUtils.YYYY_MM_DD_HH_MM_SS) + ":" + risk.getReason(),
                        ServiceCode.RISK_WITHDRAW.getCode(),
                        risk.getRiskId()
                );
            }
        }
    }
}
