package org.dromara.mp.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ibm.icu.text.SimpleDateFormat;
import com.tencentcloudapi.common.AbstractModel;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.faceid.v20180301.FaceidClient;
import com.tencentcloudapi.faceid.v20180301.models.*;
import com.tencentcloudapi.ocr.v20181119.OcrClient;
import com.tencentcloudapi.ocr.v20181119.models.BankCardOCRRequest;
import com.tencentcloudapi.ocr.v20181119.models.BankCardOCRResponse;
import com.tencentcloudapi.ocr.v20181119.models.IDCardOCRRequest;
import com.tencentcloudapi.ocr.v20181119.models.IDCardOCRResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.service.BaseService;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.entity.UploadResult;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.common.satoken.utils.MpLoginHelper;
import org.dromara.map.api.domain.RemoteUserWorkerVo;
import org.dromara.map.api.model.LoginMpUser;
import org.dromara.mp.domain.UserWorker;
import org.dromara.mp.domain.UserWorkerAccount;
import org.dromara.mp.domain.bo.UserWorkerBo;
import org.dromara.mp.domain.vo.*;
import org.dromara.mp.exception.BankCard4Exception;
import org.dromara.mp.exception.MpException;
import org.dromara.mp.mapper.UserWorkerAccountMapper;
import org.dromara.mp.mapper.UserWorkerMapper;
import org.dromara.mp.service.ICardIdService;
import org.dromara.mp.service.ISettlementAccountService;
import org.dromara.mp.service.ISysUnitDomainService;
import org.dromara.mp.service.IUserWorkerService;
import org.dromara.resource.api.RemoteFileService;
import org.dromara.resource.api.RemoteJzqService;
import org.dromara.resource.api.domain.RemoteFile;
import org.dromara.system.api.RemoteClientService;
import org.dromara.system.api.domain.vo.RemoteClientVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author sunzexing
 * @version 1.0
 * @title CardIdService
 * @description 身份信息
 * @create 2024-04-01 17:34
 */
@Service
@Slf4j
public class CardIdServiceImpl extends BaseService implements ICardIdService {


    @Resource
    public  ISysUnitDomainService unitDomainService;

    @Resource
    public IUserWorkerService  userWorkerService;

    @DubboReference
    public RemoteFileService remoteFileService;


    @DubboReference
    public  RemoteClientService remoteClientService;

    @DubboReference
    public RemoteJzqService remoteJzqService;

    @Resource
    public ISettlementAccountService settlementAccountService;


    @Resource
    public UserWorkerAccountMapper userWorkerAccountMapper;


    @Resource
    public UserWorkerMapper  userWorkerMapper;


    public  static final long MAXSIZE = 1024*1024*5;


    /***
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-08 14:13
     * 说明：银行卡4要素认证
     **/

    @Override
    public Map bankAuth4(String cardNo,String code,String bankImg,
                         String bankInfo,String cardType,String cardName,String phone,String channelName)throws Exception{
        Map result = new HashMap();

        if(StringUtils.isEmpty(phone)){
            this.invalidationParamsException("银行预留手机号不能为空");
        }

        if(StringUtils.isEmpty(bankInfo)){
            this.invalidationParamsException("银行信息不能为空");
        }

        if(StringUtils.isEmpty(cardNo)){
            this.invalidationParamsException("银行卡号不能为空");
        }
        Long userId = MpLoginHelper.getUserId();
        UserWorkerVo  userWorker =  this.userWorkerService.queryById(userId);
        ThirdConf tc = this.getThirdConfig(code,"bankCard4Config");
        boolean  tag =  this.bankCard3(cardNo,userWorker.getName(),userWorker.getCardId());
        if(tag){
          int i =  this.settlementAccountService.addAccount(bankInfo,userWorker.getName(),cardNo,channelName,phone,bankImg,cardType);
          if( i <= 0){
             this.invalidationParamsException("添加银行卡失败!");
          }
        }

        UserWorkerBo bo = new UserWorkerBo();
        bo.setId(userWorker.getId());
        bo.setIsAuthentication(1L);
        bo.setUpdateTime(new Date());
        this.userWorkerService.updateByBo(bo);
        result.put("resultTag",tag);
        return result;
    }




    @Override
    @Transactional
    public Boolean mdyBank(String cardNo,String code,String bankImg,
                         String bankInfo,String cardType,String cardName,String phone,Long id)throws Exception {

        if(id == null){
            this.invalidationParamsException("银行卡ID不能为空");
        }

        if(StringUtils.isEmpty(phone)){
            this.invalidationParamsException("银行预留手机号不能为空");
        }

        if(StringUtils.isEmpty(bankInfo)){
            this.invalidationParamsException("银行信息不能为空");
        }

        if(StringUtils.isEmpty(cardNo)){
            this.invalidationParamsException("银行卡号不能为空");
        }

        Long userId = MpLoginHelper.getUserId();
        UserWorkerVo  userWorker =  this.userWorkerService.queryById(userId);
        ThirdConf tc = this.getThirdConfig(code,"bankCard4Config");
        boolean  tag =  this.bankCard3(cardNo,userWorker.getName(),userWorker.getCardId());


        UserWorkerAccountVo uwav = this.userWorkerAccountMapper.selectVoById(id);

        if(uwav != null && uwav.getBankCard().equals(cardNo) &&uwav.getBankType().equals(bankInfo)){
            UserWorkerAccount  userWorkerAccount = new UserWorkerAccount();
            userWorkerAccount.setId(id);
            userWorkerAccount.setBankCardPic(bankImg);
            userWorkerAccount.setBankType(bankInfo);
            userWorkerAccount.setUpdateBy(MpLoginHelper.getUserId());
            userWorkerAccount.setUpdateTime(new Date());
            userWorkerAccount.setCardType(cardType);
            userWorkerAccount.setPhone(phone);
            this.userWorkerAccountMapper.updateById(userWorkerAccount);

        }else{
            UserWorkerAccount  userWorkerAccount = new UserWorkerAccount();
            userWorkerAccount.setId(id);
            userWorkerAccount.setIsDefault(0L);
            userWorkerAccount.setStatus(0);
            this.userWorkerAccountMapper.updateById(userWorkerAccount);
            int i =  this.settlementAccountService.addAccount(bankInfo,userWorker.getName(),cardNo,uwav.getPassage(),phone,bankImg,cardType);
            if( i <= 0){
                this.invalidationParamsException("修改银行卡失败!");
            }

        }

        return true;
    }

    @Override
    public Map getUserInfo() {
        Map  paraMap = new HashMap();
        UserWorkerVo  vo =  this.userWorkerService.queryById(MpLoginHelper.getUserId());
        paraMap.put("name",vo.getName());
        paraMap.put("phone",vo.getPhone());
        paraMap.put("isAuth",vo.getIsAuth());
        paraMap.put("isAuthentication",vo.getIsAuthentication());
        paraMap.put("isFaceAuth",vo.getIsFaceAuth());
        return paraMap;
    }


    /***
     * 身份证识别
     * @param file
     * @param type
     * @param code
     * @return
     * @throws Exception
     */

    public Map  idCardOcr(MultipartFile file, String type,String code) throws Exception{

        Map resultMap = new HashMap();

        try{
            String imagestr = null;
            if(file.getSize() > MAXSIZE){
                imagestr = org.dromara.mp.util.ImgUtil.scaleImgToBase64(file.getInputStream(),0.8f);
            }else{
                imagestr = Base64.encode(file.getInputStream());
            }
            if(StringUtils.isEmpty(imagestr)){
                invalidationParamsException("base64编码出错");
            }
//            ThirdConf thirdConf = this.getThirdConfig(code,"idcardConfig");
//            LoginMpUser userWorkerVo =  MpLoginHelper.getLoginUser();
//            UserWorkerVo  resultWorkerVo = this.cardIdOcr(userWorkerVo.getPhone(),imagestr,thirdConf,type);


            String resultFile;

            if (type.equals("FRONT")){
                resultFile = remoteJzqService.ocrIdentity(imagestr,1);
                JSONObject jsonObject = JSONObject.parseObject(resultFile);
                if (jsonObject.getString("success").equals("false")){
                    this.invalidationParamsException("身份证正面识别失败");
                }
                JSONObject data = jsonObject.getJSONObject("data");
                IdCardVo idCardVo =  data.toJavaObject(IdCardVo.class);
                String birthday = convertDateFormat(idCardVo.getBirthday());
                LocalDate localDate = LocalDate.parse(birthday, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                java.sql.Date sqlDate = java.sql.Date.valueOf(localDate);

                resultMap.put("name", idCardVo.getName());
                resultMap.put("cardId", idCardVo.getIdNo());
                resultMap.put("address", idCardVo.getAddress());
                resultMap.put("birthday", sqlDate);
                resultMap.put("sex", idCardVo.getGender());
                resultMap.put("nation", idCardVo.getNation());
            }else {
                resultFile = remoteJzqService.ocrIdentity(imagestr,0);
                JSONObject jsonObject = JSONObject.parseObject(resultFile);
                if(jsonObject.getString("success").equals("false")){
                    this.invalidationParamsException("身份证反面识别失败");
                }
                JSONObject data = jsonObject.getJSONObject("data");
                IdCardVo idCardVo =  data.toJavaObject(IdCardVo.class);
                String issueDate = convertDateFormat(idCardVo.getIssuingTime());
                String expiryDate = convertDateFormat(idCardVo.getOverdueTime());
                LocalDate localDate = LocalDate.parse(issueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                LocalDate localDate1 = LocalDate.parse(expiryDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                resultMap.put("issue", idCardVo.getIssuingAuthority());
                resultMap.put("issueDate", localDate);
                resultMap.put("expiryDate", localDate1);

            }

            String originalFilename =  file.getOriginalFilename();
            String contentType = file.getContentType();
            RemoteFile remoteFile =  remoteFileService.upload(UUID.fastUUID().toString(),originalFilename,contentType,file.getBytes());

            resultMap.put("cardImg",remoteFile.getUrl());
            resultMap.put("ossId",remoteFile.getOssId());
        }catch (Exception e){
            e.printStackTrace();
            log.error("身份证识别报错===>"+e.getMessage());
            throw  e;
        }
        return  resultMap;
    }

    private String convertDateFormat(String dateStr) {
        if (dateStr == null || dateStr.length() != 8) {
            throw new IllegalArgumentException("日期格式不正确，应为 yyyyMMdd");
        }
        return dateStr.substring(0, 4) + "-" + dateStr.substring(4, 6) + "-" + dateStr.substring(6, 8);
    }

    /***
     * 银行卡图片识别
     * @param file
     * @param type
     * @param code
     * @return
     * @throws Exception
     */
    @Override
    public Map bankUploadOcr(MultipartFile file, String type, String code) throws Exception {

        Map resultMap = new HashMap();
//        String imagestr = null;
//        if(file.getSize() > MAXSIZE){
//            imagestr = org.dromara.mp.util.ImgUtil.scaleImgToBase64(file.getInputStream(),0.8f);
//        }else{
//            imagestr = Base64.encode(file.getInputStream());
//        }
//
//        if(StringUtils.isEmpty(imagestr)){
//            invalidationParamsException("base64编码出错");
//        }

        File file1 = new File(file.getOriginalFilename());
        try (FileOutputStream fos = new FileOutputStream(file1)) {
            fos.write(file.getBytes());  // 将字节流写入文件
        }

//        ThirdConf thirdConf = this.getThirdConfig(code,"bankCardOcrConfig");
//
//        BankCardVo  bankCardVo =  this.bankCardOcr(null,imagestr,thirdConf);

        String result = remoteJzqService.ocrBank(file1);
        JSONObject jsonObject = JSONObject.parseObject(result);
        JSONObject data = jsonObject.getJSONObject("data");
        BankCardOcrVo bankCardVo =  data.toJavaObject(BankCardOcrVo.class);


        String originalFilename =  file.getOriginalFilename();
        String contentType = file.getContentType();
        RemoteFile remoteFile =  remoteFileService.upload(UUID.fastUUID().toString(),originalFilename,contentType,file.getBytes());

        resultMap.put("cardName",bankCardVo.getBankName());
        resultMap.put("cardNo",bankCardVo.getCardNo());
//        resultMap.put("bankInfo",bankCardVo.getBankInfo().replaceAll("[\\d()]",""));
        resultMap.put("validDate",bankCardVo.getValidDate());
//        resultMap.put("cardType",bankCardVo.getCardType());
        resultMap.put("orderNo",bankCardVo.getOrderNo());
        resultMap.put("bankImg",remoteFile.getUrl());
        resultMap.put("ossId",remoteFile.getOssId());

        return resultMap;
    }




    /**
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-07 19:28
     * 说明：
     **/
    @Override
    @Transactional
    public Map submitIdCardInfo(UserWorkerBo userWorkerBo,String code)throws Exception {

        Map resultMap = new HashMap();

        if(StringUtils.isEmpty(code)){
            throw new MpException("唯一码不能为空");
        }

        if(isIDCardExpired(userWorkerBo.getExpiryDate())){
            throw new MpException("身份证已过期");
        }


        ThirdConf thirdConf = this.getThirdConfig(code,"idcardAuthConfig");
        //身份证二要素
      //  boolean tag = this.cardId2(userWorkerBo.getName(), userWorkerBo.getCardId(),thirdConf);
        String s = remoteJzqService.userValid(userWorkerBo.getName(), userWorkerBo.getCardId());
        JSONObject json = JSONObject.parseObject(s);
        JSONObject data = json.getJSONObject("data");
        if(data.get("valid").equals("false")){
            throw new MpException(data.getString("message"));
        }

        //更新数据
        long userId = MpLoginHelper.getUserId();
        UserWorkerVo  uwv = this.userWorkerService.queryById(userId);
        if(uwv == null){
            throw new MpException("非法用户");
        }
        if(StringUtils.isNotEmpty(uwv.getCardId())){
            if(!uwv.getCardId().equals(userWorkerBo.getCardId())){
                throw new MpException("登录账号身份证不一致");
            }
        }
        UserWorkerBo paramBo = new UserWorkerBo();
        paramBo.setCardId(userWorkerBo.getCardId());
        List<UserWorkerVo>  selList =  this.userWorkerService.queryList(paramBo);
        if(selList != null && !selList.isEmpty()){
            int  size = selList.size();
            if(size > 1){
                throw new MpException("身份证已绑定");
            }else{
                UserWorkerVo vo = selList.get(0);
                if(StringUtils.isEmpty(vo.getPhone())){
                    //更新手机号
                    vo.setPhone(uwv.getPhone());
                    List delList = new ArrayList();
                    delList.add(userId);
                    boolean delTag  = this.userWorkerService.deleteWithValidByIds(delList,true);
                    if(delTag){
                        UserWorkerBo  upUserBo = new UserWorkerBo();
                        upUserBo.setId(vo.getId());
                        upUserBo.setPhone(uwv.getPhone());
                        upUserBo.setStatus(1);
                        upUserBo.setUpdateTime(new Date());
                        this.userWorkerService.updateByBo(upUserBo);
                        //更新缓存信息
                        LoginMpUser loginMpUser = new LoginMpUser();
                        loginMpUser.setUserId(vo.getId());
                        loginMpUser.setPhone(vo.getPhone());
                        loginMpUser.setName(vo.getName());
                        String clientId = MpLoginHelper.getExtra(MpLoginHelper.CLIENT_KEY).toString();
                        RemoteClientVo client = remoteClientService.queryByClientId(clientId);
                        SaLoginModel model = new SaLoginModel();
                        model.setDevice(client.getDeviceType());
                        model.setTimeout(client.getTimeout());
                        model.setActiveTimeout(client.getActiveTimeout());
                        model.setExtra(MpLoginHelper.CLIENT_KEY, client.getClientId());
                        MpLoginHelper.login(loginMpUser,null, model);
                        Map tokenMap = new HashMap();
                        tokenMap.put("access_token",StpUtil.getTokenValue());
                        tokenMap.put("refresh_token",StpUtil.getTokenValue());
                        resultMap.put("token",tokenMap);
                        userId = vo.getId();
//                        MpLoginHelper.setLoginInfo(loginMpUser);
                    }

                }else if(!vo.getId().equals(userId)){
                    throw new MpException("身份证已绑定");
                }
            }
        }


        thirdConf = this.getThirdConfig(code,"faceAuthConfig");

       Date currentDate = new Date();
//       FaceAuth faceAuth =  this.faceAuth(thirdConf.getRuleId(), thirdConf.getRedirectUrl(),userWorkerBo.getName(), userWorkerBo.getCardId(),thirdConf);
//       resultMap.put("redirectUrl",faceAuth.getRedirectUrl());



        String orderNo = "XZS1974";
        String s1 = remoteJzqService.startH5Face(orderNo, userWorkerBo.getName(), userWorkerBo.getCardId(), thirdConf.getRedirectUrl(), 1);
        JSONObject result = JSONObject.parseObject(s1);
        if(result.getString("success").equals("false")){
            log.error(result.getString("msg"));
            throw new MpException(result.getString("msg"));
        }
        JSONObject result1 = result.getJSONObject("data");

        resultMap.put("redirectUrl", result1.getString("startFaceUrl"));

        userWorkerBo.setId(userId);
        userWorkerBo.setBizToken("81EEF6178-28EE-4759-A823E-6CBBBE6BC442");
        userWorkerBo.setTokenExpirDate(DateUtil.offsetSecond(currentDate,7200));
        userWorkerBo.setIsAuth(1L);
        userWorkerBo.setEditTime(currentDate);
        userWorkerBo.setIsFaceAuth(1);
        this.userWorkerService.updateByBo(userWorkerBo);
        //人脸核验url
        return resultMap;

    }


    @Override
    public Map  getFaceAuth(String code)throws Exception{

        if(StringUtils.isEmpty(code)){
            this.invalidationParamsException("唯一码不能为空");
        }

        UserWorkerVo uwv = this.userWorkerService.queryById(MpLoginHelper.getUserId());

        if(uwv == null || uwv.getIsAuth() == null || uwv.getIsAuth().intValue() != 1){
            this.invalidationParamsException("未完成实名认证");
        }
        Map resultMap = new HashMap();



        ThirdConf  thirdConf = this.getThirdConfig(code,"faceAuthConfig");

        String orderNo = "XZS9740";

        String s1 = remoteJzqService.startH5Face(orderNo, uwv.getName(), uwv.getCardId(), thirdConf.getRedirectUrl(), 1);
        JSONObject result = JSONObject.parseObject(s1);
        if(result.getString("success").equals("false")){
            log.error(result.getString("msg"));
            throw new MpException(result.getString("msg"));
        }
        JSONObject result1 = result.getJSONObject("data");

        resultMap.put("redirectUrl", result1.getString("startFaceUrl"));

//        FaceAuth faceAuth =  this.faceAuth(thirdConf.getRuleId(), thirdConf.getRedirectUrl(),uwv.getName(), uwv.getCardId(),thirdConf);
//        resultMap.put("redirectUrl",faceAuth.getRedirectUrl());
        Date currentDate = new Date();
        UserWorkerBo userWorkerBo = new UserWorkerBo();
        userWorkerBo.setId(MpLoginHelper.getUserId());
        userWorkerBo.setBizToken("81EEF6178-28EE-4759-A823E-6CBBBE6BC442");
        userWorkerBo.setTokenExpirDate(DateUtil.offsetSecond(currentDate,7200));
        userWorkerBo.setEditTime(currentDate);
        this.userWorkerService.updateByBo(userWorkerBo);
        return resultMap;
    }


    /****
     * 获取人审核的结果
     * @param bizToken
     * @param code 唯一码
     * @return
     * @throws Exception
     */
    @Override
    public String getFaceAuthResult(String bizToken,String code)throws Exception {

        if(StringUtils.isEmpty(bizToken)){
            this.invalidationParamsException("人脸核验token不能为空!");
        }
        ThirdConf thirdConf = this.getThirdConfig(code,"faceAuthConfig");

        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.eq("biz_token",bizToken);
        UserWorker uw = this.userWorkerMapper.selectOne(wrapper);
        if(uw == null){
            return "";
        }

       RemoteFile  remoteFile =  this.getDectInfo(null,bizToken,thirdConf);
        if(remoteFile != null && StringUtils.isNotEmpty(remoteFile.getUrl())){
            UserWorker uwk = new UserWorker();
            uwk.setId(uw.getId());
            uwk.setIsFaceAuth(1);
            uwk.setPhotoPath(remoteFile.getUrl());
            uwk.setUpdateTime(new Date());
            this.userWorkerMapper.updateById(uwk);
        }
        return "1";
    }

    @Override
    public Map getUserCardInfo() {
        UserWorkerVo uwv = this.userWorkerMapper.selectVoById(MpLoginHelper.getUserId());
        Map resultMap = new HashMap();

        resultMap.put("name",uwv.getName());
        resultMap.put("cardId",uwv.getCardId());
        resultMap.put("cardPositive",uwv.getCardPositive());
        resultMap.put("cardBack",uwv.getCardBack());
        resultMap.put("is_auth",uwv.getIsAuth());
        return resultMap;
    }


    public static boolean isIDCardExpired(String endDateStr) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date endDate;
        try {

            if(endDateStr.contains("长期")){
                return false;
            }
            endDate = sdf.parse(endDateStr);
            Date currentDate = new Date(); // 获取当前日期
            // 比较当前日期和身份证有效期结束日期
            if (currentDate.after(endDate)) {
                return true; // 当前日期在有效期之后，身份证已过期
            } else {
                return false; // 当前日期在有效期内，身份证未过期
            }
        } catch (ParseException e) {
            e.printStackTrace();
            return false; // 如果无法解析有效期结束日期，则默认返回未过期
        }
    }

    private  ThirdConf  getThirdConfig(String code,String type ){

        Map configMap = this.unitDomainService.mpOtherThirdConfig(code);
        if(configMap == null){
            throw new MpException("第三方参数未配置!");
        }
        Map subMap = (Map) configMap.get(type);
        ThirdConf thirdConf = JsonUtils.parseObject(JsonUtils.toJsonString(subMap),ThirdConf.class);

        return thirdConf;
    }


    /**
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-08 9:25
     * 说明：身份证二要素认证
     **/
    private boolean cardId2(String name,String idCard,ThirdConf config) throws Exception{
        try{
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential  crd = new Credential(config.getSecretId(),config.getSecretKey());

            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile hpf = new HttpProfile();
            hpf.setEndpoint(config.getEndPoint());

            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(hpf);
            // 实例化要请求产品的client对象,clientProfile是可选的
            FaceidClient client = new FaceidClient(crd, config.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            IdCardVerificationRequest req = new IdCardVerificationRequest();

            req.setName(name);
            req.setIdCard(idCard);
            // 返回的resp是一个IDCardOCRResponse的实例，与请求对象对应
            IdCardVerificationResponse  resp = client.IdCardVerification(req);
            log.info("身份证二要素识姓名:["+name+"],idcard["+idCard+"]别返回结果: "+ AbstractModel.toJsonString(resp));
            if("0".equals(resp.getResult())){
                return true;
            }else{
                throw new MpException(resp.getDescription());
            }
        }catch(TencentCloudSDKException e){
            log.error("身份证二要素认证出错:姓名:{},身份证号{},错误信息{}",name,idCard,e.getMessage());
            throw e;
        }catch (Exception e){
            log.error("身份证二要素认证出错:姓名:{},身份证号{},错误信息{}",name,idCard,e.getMessage());
            throw e;
        }
    }

    /*
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-02 13:36
     * 说明：
     **/
    private UserWorkerVo  cardIdOcr(String phone,String base64ImgStr,ThirdConf config,String cardType)throws Exception{

        try{
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential  crd = new Credential(config.getSecretId(),config.getSecretKey());

            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile hpf = new HttpProfile();
            hpf.setEndpoint(config.getEndPoint());

            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(hpf);
            // 实例化要请求产品的client对象,clientProfile是可选的
            OcrClient client = new OcrClient(crd, config.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            IDCardOCRRequest req = new IDCardOCRRequest();
            req.setImageBase64(base64ImgStr);
            req.setCardSide(cardType);
            // 返回的resp是一个IDCardOCRResponse的实例，与请求对象对应
            IDCardOCRResponse resp = client.IDCardOCR(req);
            log.info("身份证识别:["+phone+"]返回结果: "+ AbstractModel.toJsonString(resp));

            UserWorkerVo  user = new UserWorkerVo();
            user.setName(resp.getName());
            user.setCardId(resp.getIdNum());
            user.setAddress(resp.getAddress());
            user.setBirthday(DateUtil.parse(resp.getBirth()));
            user.setSex(resp.getSex());
            user.setNation(resp.getNation());
            user.setIssue(resp.getAuthority());
            String validDate = resp.getValidDate();
            if(StringUtils.isNotEmpty(validDate)){
                String[] vs = validDate.split("-");
                if( vs.length >1){
                    user.setIssueDate(DateUtil.parseDate(vs[0].trim().replaceAll("\\.","-")));
                    user.setExpiryDate(vs[1].trim().replaceAll("\\.","-"));
                }
            }
            return user;
        }catch(TencentCloudSDKException e){
            log.error("身份证OCR识别出错:手机号:{},状态码{},错误信息{}",phone,e.getErrorCode(),e.getMessage());
            throw e;

        }catch (Exception e){
            log.error("身份证OCR识别出错:手机号:{},错误信息{}",phone,e.getMessage());
            throw e;
        }
    }




    /*
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-02 13:36
     * 说明：银行卡识别
     **/
    private BankCardVo bankCardOcr(String phone, String base64ImgStr,ThirdConf config)throws Exception{

        try{
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential  crd = new Credential(config.getSecretId(), config.getSecretKey());

            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile hpf = new HttpProfile();
            hpf.setEndpoint(config.getEndPoint());

            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(hpf);
            // 实例化要请求产品的client对象,clientProfile是可选的
            OcrClient client = new OcrClient(crd, config.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            BankCardOCRRequest req = new BankCardOCRRequest();

            req.setImageBase64(base64ImgStr);
            // 返回的resp是一个IDCardOCRResponse的实例，与请求对象对应
            BankCardOCRResponse resp = client.BankCardOCR(req);
            log.info("银行卡识别:["+phone+"]返回结果: "+ AbstractModel.toJsonString(resp));

            BankCardVo  backCard = new BankCardVo();
            backCard.setCardName(resp.getCardName());
            backCard.setCardNo(resp.getCardNo());
            backCard.setBankInfo(resp.getBankInfo());
            backCard.setCardType(resp.getCardType());
            return backCard;
        }catch(TencentCloudSDKException e){
            log.error("银行卡OCR识别出错:手机号:{},状态码{},错误信息{}",phone,e.getErrorCode(),e.getMessage());
            throw e;
        }catch (Exception e){
            log.error("银行卡OCR识别出错:手机号:{},错误信息{}",phone,e.getMessage());
            throw e;
        }
    }




    /*
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-02 13:50
     * 说明：银行卡三要素认证
     **/
    private boolean bankCard3(String bankCard,String name,String idCard)throws Exception{
        JSONObject result = JSONObject.parseObject( remoteJzqService.bankThreeVerify(name,idCard,bankCard));
        if(result.getString("success").equals("false")){
            log.error("银行卡三要素认证失败:银行卡号:{},姓名:{},身份证号:{},原因:{}",bankCard,name,idCard,result.getString("msg"));
            throw new Exception(result.getString("msg"));
        }
        return result.getString("success").equals("true");
    }





    /*
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-02 13:50
     * 说明：银行卡四要素认证
     **/
    private boolean bankCard4(String bankCard,String name,String phone,String idCard,ThirdConf conf)throws Exception{

        try{
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential cred = new Credential(conf.getSecretId(), conf.getSecretKey());
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            // 推荐使用北极星，相关指引可访问如下链接
            // https://git.woa.com/tencentcloud-internal/tencentcloud-sdk-java#%E5%8C%97%E6%9E%81%E6%98%9F
            httpProfile.setEndpoint(conf.getEndPoint());
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            FaceidClient client = new FaceidClient(cred, conf.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            BankCard4EVerificationRequest req = new BankCard4EVerificationRequest();
            req.setName(name);
            req.setBankCard(bankCard);
            req.setIdCard(idCard);
            req.setPhone(phone);
            // 返回的resp是一个BankCard4EVerificationResponse的实例，与请求对象对应
            BankCard4EVerificationResponse resp = client.BankCard4EVerification(req);
            log.info("银行卡四要素:["+bankCard+","+name+","+phone+","+idCard+"]返回结果: "+ AbstractModel.toJsonString(resp));

            if("0".equals(resp.getResult())){
                return true;
            }else{
                throw new BankCard4Exception(resp.getDescription());
            }
        } catch (TencentCloudSDKException e) {
            log.error("银行卡四要素认证出错:手机号:{},姓名{},身份证{},银行卡{},状态码{},错误信息{}",phone,name,idCard,bankCard,e.getErrorCode(),e.getMessage());
            throw  e;
        } catch(Exception e){
            e.printStackTrace();
            log.error("银行卡四要素认证出错:手机号:{},姓名{},身份证{},银行卡{},错误信息{}",phone,name,idCard,bankCard,e.getMessage());
            throw e;
        }
    }



    /*
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-02 14:10
     * 说明：人脸核验获取BizToken
     **/
    private FaceAuth  faceAuth(String ruleId,String redirectUrl,String name,String idCard,ThirdConf conf) throws Exception{
        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential cred = new Credential(conf.getSecretId(), conf.getSecretKey());
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            // 推荐使用北极星，相关指引可访问如下链接
            // https://git.woa.com/tencentcloud-internal/tencentcloud-sdk-java#%E5%8C%97%E6%9E%81%E6%98%9F
            httpProfile.setEndpoint(conf.getEndPoint());
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            FaceidClient client = new FaceidClient(cred, conf.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DetectAuthRequest req = new DetectAuthRequest();
            req.setIdCard(idCard);
            req.setName(name);
            req.setRedirectUrl(redirectUrl);
            req.setRuleId(ruleId);
            // 返回的resp是一个DetectAuthResponse的实例，与请求对象对应
            DetectAuthResponse resp = client.DetectAuth(req);
            FaceAuth fa = new FaceAuth();
            fa.setRedirectUrl(resp.getUrl());
            fa.setBizToken(resp.getBizToken());
            return fa;

        } catch (TencentCloudSDKException e) {
            log.error("人脸核验获取BizToken:状态码{},错误信息{}", e.getErrorCode(), e.getMessage());
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("人脸核验获取BizToken,错误信息{}", e.getMessage());
            throw e;
        }

    }



    /*
     * @Param
     * @Return
     * @Author sunzexing
     * @Date 2024-04-02 14:10
     * 说明：人脸核验结果
     **/
    private RemoteFile  getDectInfo(String ruleId,String bizToken,ThirdConf conf) throws Exception{
        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential cred = new Credential(conf.getSecretId(), conf.getSecretKey());
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            // 推荐使用北极星，相关指引可访问如下链接
            // https://git.woa.com/tencentcloud-internal/tencentcloud-sdk-java#%E5%8C%97%E6%9E%81%E6%98%9F
            httpProfile.setEndpoint(conf.getEndPoint());
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            FaceidClient client = new FaceidClient(cred, conf.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            GetDetectInfoEnhancedRequest req = new GetDetectInfoEnhancedRequest();

            req.setRuleId(conf.getRuleId());
            req.setBizToken(bizToken);

            // 返回的resp是一个GetDetectInfoResponse的实例，与请求对象对应
            GetDetectInfoEnhancedResponse resp = client.GetDetectInfoEnhanced(req);

            if(resp.getText() != null && resp.getText().getErrCode() == 0){
                DetectInfoBestFrame baseFrame = resp.getBestFrame();
                if(baseFrame != null){
                    String bestBase64 = baseFrame.getBestFrame();
                    byte[]  face = Base64.decode(bestBase64);
                    String fileName = UUID.fastUUID().toString();
                    RemoteFile  file = this.remoteFileService.upload(fileName,fileName+".png","image/png",face);
                    return file;
                }
                return new RemoteFile();
            }else{
                throw new RuntimeException(resp.getText().getErrMsg());
            }
        } catch (TencentCloudSDKException e) {
            log.error("查询人脸核验结果:状态码{},错误信息{}", e.getErrorCode(), e.getMessage());
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询人脸核验结果,错误信息{}", e.getMessage());
            throw e;
        }
    }



}


@Data
class FaceAuth {

    //核验流程唯一密钥
    private String bizToken;

    //用于发起核身流程的 URL
    private String redirectUrl;
}


@Data
class ThirdConf{

    private String  type;

    private String secretId;

    private String secretKey;

    private String endPoint;

    private String ruleId;

    private String redirectUrl;

    private String region;

}
