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

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

import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.ss.risk.service.RiskService;
import com.ruoyi.ss.riskInfo.domain.dto.RiskInfoVerifyDTO;
import com.ruoyi.ss.riskInfo.domain.enums.RiskInfoStatus;
import com.ruoyi.ss.riskInfo.service.RiskInfoValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.ss.riskInfo.mapper.RiskInfoMapper;
import com.ruoyi.ss.riskInfo.domain.RiskInfo;
import com.ruoyi.ss.riskInfo.domain.RiskInfoVO;
import com.ruoyi.ss.riskInfo.domain.RiskInfoQuery;
import com.ruoyi.ss.riskInfo.service.RiskInfoService;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 风控材料Service业务层处理
 *
 * @author ruoyi
 * @date 2024-11-25
 */
@Service
public class RiskInfoServiceImpl implements RiskInfoService
{
    @Autowired
    private RiskInfoMapper riskInfoMapper;

    @Autowired
    private RiskInfoValidator riskInfoValidator;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private RiskService riskService;

    @Autowired
    private RedisLock redisLock;

    /**
     * 查询风控材料
     *
     * @param infoId 风控材料主键
     * @return 风控材料
     */
    @Override
    public RiskInfoVO selectRiskInfoByInfoId(Long infoId)
    {
        return riskInfoMapper.selectRiskInfoByInfoId(infoId);
    }

    /**
     * 查询风控材料列表
     *
     * @param riskInfo 风控材料
     * @return 风控材料
     */
    @Override
    public List<RiskInfoVO> selectRiskInfoList(RiskInfoQuery riskInfo)
    {
        return riskInfoMapper.selectRiskInfoList(riskInfo);
    }

    /**
     * 新增风控材料
     *
     * @param riskInfo 风控材料
     * @return 结果
     */
    @Override
    public int insertRiskInfo(RiskInfo riskInfo) {
        // 校验
        riskInfoValidator.preCheck(riskInfo);
        riskInfo.setCreateTime(DateUtils.getNowDate());
        return riskInfoMapper.insertRiskInfo(riskInfo);
    }

    /**
     * 修改风控材料
     *
     * @param riskInfo 风控材料
     * @return 结果
     */
    @Override
    public int updateRiskInfo(RiskInfo riskInfo) {
        // 校验
        riskInfoValidator.preCheck(riskInfo);
        return riskInfoMapper.updateRiskInfo(riskInfo);
    }

    /**
     * 批量删除风控材料
     *
     * @param infoIds 需要删除的风控材料主键
     * @return 结果
     */
    @Override
    public int deleteRiskInfoByInfoIds(Long[] infoIds)
    {
        return riskInfoMapper.deleteRiskInfoByInfoIds(infoIds);
    }

    /**
     * 删除风控材料信息
     *
     * @param infoId 风控材料主键
     * @return 结果
     */
    @Override
    public int deleteRiskInfoByInfoId(Long infoId)
    {
        return riskInfoMapper.deleteRiskInfoByInfoId(infoId);
    }

    @Override
    public int submit(Long infoId) {
        if (infoId == null) {
            return 0;
        }

        // 校验数据
        RiskInfoVO old = this.selectRiskInfoByInfoId(infoId);
        ServiceUtil.assertion(old == null || old.getRiskId() == null, "待提交的数据不存在");
        Long lockKey = old.getRiskId();
        ServiceUtil.assertion(!redisLock.lock(RedisLockKey.SUBMIT_RISK_INFO, lockKey), "正在处理，请勿重复提交");

        try {
            // 校验
            riskInfoValidator.preSubmitCheck(old);
            // 操作
            Integer result = transactionTemplate.execute(status -> {
                RiskInfoVO data = new RiskInfoVO();
                data.setSubmitTime(LocalDateTime.now());
                data.setStatus(RiskInfoStatus.WAIT_VERIFY.getStatus());
                RiskInfoQuery query = new RiskInfoQuery();
                query.setInfoId(infoId);
                query.setStatusList(RiskInfoStatus.canSubmit());
                int submit = this.updateByQuery(data, query);
                ServiceUtil.assertion(submit != 1, "提交失败");

                // 若开启了提交后自动通过，则直接通过
                if (old.getRiskUnsealSelf() != null && old.getRiskUnsealSelf()) {
                    RiskInfoVerifyDTO dto = new RiskInfoVerifyDTO();
                    dto.setInfoId(infoId);
                    dto.setPass(true);
                    dto.setVerifyRemark("免审核通过");
                    this.verify(dto, LoginUser.system());
                }

                return submit;
            });

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

    }

    @Override
    public int updateRealName(Long infoId, Long realNameId) {
        if (infoId == null || realNameId == null) {
            return 0;
        }
        RiskInfo data = new RiskInfo();
        data.setInfoId(infoId);
        data.setRealNameId(realNameId);
        return this.updateRiskInfo(data);
    }

    @Override
    public int verify(RiskInfoVerifyDTO dto, LoginUser verifier) {
        ServiceUtil.assertion(dto == null, "参数错误");

        RiskInfoVO old = selectRiskInfoByInfoId(dto.getInfoId());
        ServiceUtil.assertion(old == null, "待审核的风控材料不存在");
        ServiceUtil.assertion(!RiskInfoStatus.canVerify().contains(old.getStatus()), "风控材料当前状态不允许审核");

        Integer result = transactionTemplate.execute(status -> {
            // 修改审核状态
            RiskInfo data = new RiskInfo();
            data.setStatus(dto.getPass() ? RiskInfoStatus.PASS.getStatus() : RiskInfoStatus.REJECT.getStatus());
            data.setVerifyId(verifier.getUserId());
            data.setVerifyBy(verifier.getUsername());
            data.setVerifyTime(LocalDateTime.now());
            data.setVerifyRemark(dto.getVerifyRemark());
            RiskInfoQuery query = new RiskInfoQuery();
            query.setInfoId(dto.getInfoId());
            query.setStatusList(RiskInfoStatus.canVerify());
            int update = this.updateByQuery(data, query);
            ServiceUtil.assertion(update != 1, "当前风控材料状态已发生变化，请刷新后重试");

            // 解封
            if (dto.getPass() != null && dto.getPass()) {
                int finish = riskService.finish(old.getRiskId());
                ServiceUtil.assertion(finish != 1, "解封失败，请重试");
            }

            return update;
        });

        return result == null ? 0 : result;
    }

    @Override
    public int selectCount(RiskInfoQuery query) {
        return riskInfoMapper.selectCount(query);
    }

    private int updateByQuery(RiskInfo data, RiskInfoQuery query) {
        return riskInfoMapper.updateByQuery(data, query);
    }
}
