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

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import com.ruoyi.bst.realName.domain.RealName;
import com.ruoyi.bst.realName.domain.RealNameQuery;
import com.ruoyi.bst.realName.domain.RealNameVO;
import com.ruoyi.bst.realName.domain.Face.Face;
import com.ruoyi.bst.realName.domain.Refresh.RealNameRefreshVO;
import com.ruoyi.bst.realName.domain.enums.RealNameStatus;
import com.ruoyi.bst.realName.mapper.RealNameMapper;
import com.ruoyi.bst.realName.service.RealNameService;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.core.redis.RedisCache;
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.common.utils.qiniu.QiNiuUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.common.valid.face.FaceResponseData;
import com.ruoyi.common.valid.face.FaceUtils;
import com.ruoyi.common.valid.face.enums.FaceIncorrect;
import com.ruoyi.common.valid.face.enums.FaceScoreResult;
import com.ruoyi.common.valid.liveness.LivenessResponseQueryData;
import com.ruoyi.common.valid.liveness.LivenessResponseTokenData;
import com.ruoyi.common.valid.liveness.LivenessUtils;
import com.ruoyi.common.valid.liveness.enums.LivenessQueryResult;
import com.ruoyi.system.user.service.UserService;

/**
 * 实名认证信息Service业务层处理
 *
 * @author ruoyi
 * @date 2025-03-29
 */
@Service
public class RealNameServiceImpl implements RealNameService
{
    @Autowired
    private RealNameMapper realNameMapper;

    // 活体检测返回地址
    public static final String LIVENESS_RETURN_URL = SpringUtils.getRequiredProperty("liveness.returnUrl");

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private UserService userService;
    @Autowired
    private TransactionTemplate transactionTemplate;

    /**
     * 查询实名认证信息
     *
     * @param id 实名认证信息主键
     * @return 实名认证信息
     */
    @Override
    public RealNameVO selectRealNameById(Long id)
    {
        return realNameMapper.selectRealNameById(id);
    }

    /**
     * 查询实名认证信息列表
     *
     * @param realName 实名认证信息
     * @return 实名认证信息
     */
    @Override
    public List<RealNameVO> selectRealNameList(RealNameQuery realName)
    {
        return realNameMapper.selectRealNameList(realName);
    }

    /**
     * 新增实名认证信息
     *
     * @param realName 实名认证信息
     * @return 结果
     */
    @Override
    public int insertRealName(RealName realName)
    {
        realName.setCreateTime(DateUtils.getNowDate());
        return realNameMapper.insertRealName(realName);
    }

    /**
     * 修改实名认证信息
     *
     * @param realName 实名认证信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateRealName(RealName realName)
    {
        realName.setUpdateTime(DateUtils.getNowDate());
        UserVO user = userService.selectUserById(realName.getUserId());
        ServiceUtil.assertion(user == null,"用户信息不存在");
        ServiceUtil.assertion(StringUtils.isBlank(realName.getUserName()), "用户姓名不允许为空");
        ServiceUtil.assertion(StringUtils.isBlank(realName.getIdCard()), "用户身份证不允许为空");

        // 构建用户信息表
        user.setUserName(realName.getUserName());
        user.setUpdateTime(DateUtils.getNowDate());
        user.setRealIdCard(realName.getIdCard());

        // 更新用户信息表
        int updateUser = userService.updateUser(user);
        ServiceUtil.assertion(updateUser != 1, "更新用户信息失败");

        // 更新实名认证表
        int updateRealName = realNameMapper.insertRealName(realName);
        ServiceUtil.assertion(updateRealName != 1, "新增实名认证失败");

        return 1;
    }

    /**
     * 批量删除实名认证信息
     *
     * @param ids 需要删除的实名认证信息主键
     * @return 结果
     */
    @Override
    public int deleteRealNameByIds(Long[] ids)
    {
        return realNameMapper.deleteRealNameByIds(ids);
    }

    /**
     * 删除实名认证信息信息
     *
     * @return 结果
     */
    @Override
    public int deleteRealNameById(Long userid)
    {

        UserVO user = new UserVO();
        user.setUserId(userid);
        user.setIsReal(false);
        RealNameVO vo = realNameMapper.selectRealNameByUserId(userid);
        if (vo != null){
            userService.updateUser(user);
            return realNameMapper.deleteRealNameByUserId(userid);
        }
       return 0;
    }

    /**
     * 实名认证
     * @param realName
     * @return
     */
    @Override
    public RealNameVO realName(RealName realName) {
        UserVO user = userService.selectUserById(realName.getUserId());
        ServiceUtil.assertion(user == null,"用户信息不存在");

        Boolean flag = realNameMapper.checkIdCard(realName.getIdCard());
        ServiceUtil.assertion(flag,"用户身份证重复");

        // 获取活体检测token
        LivenessResponseTokenData tokenData = LivenessUtils.getToken(LIVENESS_RETURN_URL, null, null);
        ServiceUtil.assertion(tokenData == null || StringUtils.isBlank(tokenData.getToken()), "获取活体检测token失败");

        // 存入缓存:10分钟
        String cacheKey = CacheConstants.LIVENESS_TOKEN + realName.getUserId();
        Face face = new Face();
        face.setUserId(realName.getUserId());
        face.setToken(tokenData.getToken());
        face.setName(realName.getUserName());
        face.setMobile(realName.getMobile());
        face.setIdCard(realName.getIdCard());
        redisCache.setCacheObject(cacheKey, face, 10, TimeUnit.MINUTES);

        // 返回数据
        RealNameVO vo = new RealNameVO();
        vo.setFaceToken(tokenData.getToken());
        vo.setJumpUrl(LivenessUtils.JUMP_URL + "?token=" + tokenData.getToken());
        return vo;
    }

    /**
     * 刷新用戶认证信息
     * @param userId
     * @return
     */
    @Override
    public RealNameRefreshVO refreshRealName(Long userId) {
        RealNameRefreshVO vo = new RealNameRefreshVO();
        vo.setPass(false);

        if (userId == null) {
            return vo;
        }

        // 通过userId获取用户提交的信息
        String cacheKey = CacheConstants.LIVENESS_TOKEN + userId;
        Face face = redisCache.getCacheObject(cacheKey);
        ServiceUtil.assertion(face == null, "token不存在");

        // 获取活体图像及三要素信息
        LivenessResponseQueryData livenessResult = LivenessUtils.queryResult(face.getToken());
        ServiceUtil.assertion(livenessResult == null, "活体信息不存在");
        ServiceUtil.assertion(!LivenessQueryResult.PASS.getResult().equals(livenessResult.getResult()), "活体检测未通过");
        ServiceUtil.assertion(StringUtils.isBlank(livenessResult.getFaceImage()), "活体检测未通过");


        // 将Base64上传到七牛云中
        String imageUrl = livenessResult.getFaceImage();
        try {
            imageUrl = QiNiuUtils.DOMAIN + "/" + QiNiuUtils.uploadBase64(imageUrl);
        } catch (Exception e) {
            throw new ServiceException("上传文件失败:" + e.getMessage());
        }

        // 判断活体是否匹配
        FaceResponseData faceIdb = FaceUtils.getFaceIdb(face.getIdCard(), face.getName(), livenessResult.getFaceImage(), null);
        ServiceUtil.assertion(faceIdb == null, "人证比对数据不存在");
        ServiceUtil.assertion(!FaceIncorrect.isSuccess(faceIdb.getIncorrect()), "人证比对未通过：" + faceIdb.getMsg());
        ServiceUtil.assertion(!FaceScoreResult.isSame(faceIdb.getScore()), "人证比对未通过，分数：" + faceIdb.getScore());

        // 通过，构造实名认证表
        RealName realName = new RealName();
        realName.setUserId(userId);
        realName.setUserName(face.getName());
        realName.setIdCard(face.getIdCard());
        realName.setMobile(face.getMobile());
        realName.setScore(faceIdb.getScore());
        realName.setPicture(imageUrl);
        realName.setStatus(RealNameStatus.REAL.getCode());
        Date now = new Date();
        realName.setUpdateTime(now);
        realName.setCreateTime(now);

        int result = this.handleNormalRealName(realName, cacheKey);
        ServiceUtil.assertion(result != 1, "实名认证失败");
        vo.setPass(true);

        return vo;
    }

    private int handleNormalRealName(RealName realName, String cacheKey) {

        // 修改实名认证信息（用户表）
        UserVO data = new UserVO();
        data.setUserId(realName.getUserId());
        data.setRealName(realName.getUserName());
        data.setRealIdCard(realName.getIdCard());
        data.setRealPhone(realName.getMobile());
        data.setIsReal(true);

        // 数据库操作
        Integer result = transactionTemplate.execute(status -> {
            // 修改用户实名信息
            int update = userService.updateUser(data);
            ServiceUtil.assertion(update != 1, "更新用户信息失败");

            // 插入实名认证表
            int insert = realNameMapper.insertRealName(realName);
            ServiceUtil.assertion(insert != 1, "新增实名认证失败");

            // 删除缓存
            redisCache.deleteObject(cacheKey);

            return update;
        });

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