package com.yn.bftl.thirdparty.modules.baiduai.util;

import com.alibaba.fastjson.JSONObject;
import com.yn.bftl.common.modules.configuration.entity.ThirdPartyPaySet;
import com.yn.bftl.thirdparty.common.exception.YnceErrorException;
import com.yn.bftl.thirdparty.common.util.HttpClientUtil;
import com.yn.bftl.thirdparty.common.util.RedisUtil;
import com.yn.bftl.thirdparty.modules.baiduai.dto.BusinessLicenseRequestDTO;
import com.yn.bftl.thirdparty.modules.baiduai.dto.IdcardRequestDTO;
import com.yn.bftl.thirdparty.modules.baiduai.vo.BankcardResponseVO;
import com.yn.bftl.thirdparty.modules.baiduai.vo.BusinessLicenseResponseVO;
import com.yn.bftl.thirdparty.modules.baiduai.vo.IdcardResponseVO;
import com.yn.bftl.thirdparty.modules.business.util.ThirdPartyConfigUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author：Vance
 * @Description：百度ai工具类
 * @Date：2022/12/20 14:02
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class BaiduaiUtil {

    private final RedisUtil redisUtil;
    private final ThirdPartyConfigUtil thirdPartyConfigUtil;

    // 请求接口域名
    private static String domainName;

    // 应用的API Key
    private static String clientId;

    // 应用的Secret Key
    private static String clientSecret;

    // 配置更新时间
    private static LocalDateTime updatedOn;

    private static final Map<String, String> IDCARD_IMAGE_STATUS_MAP = new HashMap<String, String>() {{
        put("normal", "识别正常");
        put("reversed_side", "身份证正反面颠倒");
        put("non_idcard", "上传的图片中不包含身份证");
        put("blurred", "身份证模糊");
        put("other_type_card", "其他类型证照");
        put("over_exposure", "身份证关键字段反光或过曝");
        put("over_dark", "身份证欠曝（亮度过低）");
        put("unknown", "未知状态");
    }};

    private static final Map<String, String> RISK_TYPE_MAP = new HashMap<String, String>() {{
        put("normal", "正常");
        put("copy", "复印件");
        put("temporary", "临时身份证");
        put("screen", "翻拍图片");
        put("scan", "扫描件");
        put("unknown", "其他未知情况");
    }};

    private static final Map<Integer, String> IDCARD_NUMBER_TYPE_MAP = new HashMap<Integer, String>() {{
        put(-1, "身份证正面所有字段全为空");
        put(0, "身份证证号不合法");
        put(1, "身份证证号和性别、出生信息一致");
        put(2, "身份证证号和性别、出生信息都不一致");
        put(3, "身份证证号和出生信息不一致");
        put(4, "身份证证号和性别信息不一致");
    }};

    /**
     * 初始化
     */
    private void init() {
        ThirdPartyPaySet thirdPartyPaySet = thirdPartyConfigUtil.getPlatform();
        if (thirdPartyPaySet == null) {
            throw new YnceErrorException("百度ai未配置参数");
        }
        if (StringUtils.isBlank(thirdPartyPaySet.getBaiduAiDomainName())
                || StringUtils.isBlank(thirdPartyPaySet.getBaiduAiClientId())
                || StringUtils.isBlank(thirdPartyPaySet.getBaiduAiSecretKey())) {
            throw new YnceErrorException("百度ai未配置参数");
        }
        if (thirdPartyPaySet.getUpdatedOn().equals(updatedOn)) {
            return;
        }

        updatedOn = thirdPartyPaySet.getUpdatedOn();
        domainName = thirdPartyPaySet.getBaiduAiDomainName();
        clientId = thirdPartyPaySet.getBaiduAiClientId();
        clientSecret = thirdPartyPaySet.getBaiduAiSecretKey();
    }

    /**
     * 获取 access_token
     *
     * @return
     */
    public String getAccessToken() {
        this.init();
        String redisAccessToken = redisUtil.getBaiduaiAccessToken();
        if (StringUtils.isNotEmpty(redisAccessToken)) {
            return redisAccessToken;
        }

        Map<String, Object> params = new HashMap<>();
        params.put("grant_type", "client_credentials");
        params.put("client_id", clientId);
        params.put("client_secret", clientSecret);
        JSONObject result = HttpClientUtil.getInstance().sendGet(domainName + "/oauth/2.0/token", params);
        if (result.get("error_description") != null) {
            throw new YnceErrorException(result.get("error_description").toString());
        }
        // Access Token的有效期(秒为单位，有效期30天)
        Integer expiresIn = (Integer) result.get("expires_in");
        String accessToken = (String) result.get("access_token");
        redisUtil.cacheBaiduaiAccessToken(accessToken, expiresIn);
        return accessToken;
    }

    /**
     * 身份证识别
     *
     * @param dto
     * @return
     */
    public IdcardResponseVO executeIdcardRequest(IdcardRequestDTO dto) {
        String accessToken = this.getAccessToken();
        try {
            String param = "id_card_side=" + dto.getId_card_side() + "&image=" + dto.getImage() + "&detect_risk=" + dto.getDetect_risk();
            String result = HttpUtil.post(domainName + "/rest/2.0/ocr/v1/idcard", accessToken, param);
            log.info("请求百度ai返回数据：" + result);
            IdcardResponseVO idcardResponseVO = JSONObject.parseObject(result, IdcardResponseVO.class);
            if (idcardResponseVO.getError_code() != null) {
                if (idcardResponseVO.getError_msg().contains("image format error")) {
                    throw new YnceErrorException("图片格式不支持(支持jpg/jpeg/png/bmp格式)");
                } else {
                    throw new YnceErrorException(idcardResponseVO.getError_msg());
                }
            }
            String image_status = idcardResponseVO.getImage_status();
            if (image_status != null && !image_status.equals("normal")) {
                throw new YnceErrorException(IDCARD_IMAGE_STATUS_MAP.get(image_status));
            }
            String risk_type = idcardResponseVO.getRisk_type();
            if (risk_type != null && !risk_type.equals("normal")) {
                throw new YnceErrorException(RISK_TYPE_MAP.get(risk_type));
            }
            Integer idcard_number_type = idcardResponseVO.getIdcard_number_type();
            if (idcard_number_type != null && idcard_number_type != 1) {
                throw new YnceErrorException(IDCARD_NUMBER_TYPE_MAP.get(idcard_number_type));
            }
            return idcardResponseVO;
        } catch (Exception e) {
            throw new YnceErrorException(e.getMessage());
        }
    }

    /**
     * 营业执照识别
     *
     * @param dto
     */
    public BusinessLicenseResponseVO executeBusinessLicenseRequest(BusinessLicenseRequestDTO dto) {
        String accessToken = this.getAccessToken();
        try {
            String param = "image=" + dto.getImage() + "&risk_warn=" + dto.getRisk_warn();
            String result = HttpUtil.post(domainName + "/rest/2.0/ocr/v1/business_license", accessToken, param);
            log.info("请求百度ai返回数据：" + result);
            BusinessLicenseResponseVO businessLicenseResponseVO = JSONObject.parseObject(result, BusinessLicenseResponseVO.class);
            if (businessLicenseResponseVO.getError_code() != null) {
                if (businessLicenseResponseVO.getError_msg().contains("failed to match the template")) {
                    throw new YnceErrorException("请上传正确的营业执照");
                } else if (businessLicenseResponseVO.getError_msg().contains("image format error")) {
                    throw new YnceErrorException("图片格式不支持(支持jpg/jpeg/png/bmp格式)");
                } else {
                    throw new YnceErrorException(businessLicenseResponseVO.getError_msg());
                }
            }
            String risk_type = businessLicenseResponseVO.getRisk_type();
            if (risk_type != null && !risk_type.equals("normal")) {
                throw new YnceErrorException(RISK_TYPE_MAP.get(risk_type));
            }
            return businessLicenseResponseVO;
        } catch (Exception e) {
            throw new YnceErrorException(e.getMessage());
        }
    }

    /**
     * 银行卡识别
     *
     * @param imgStr
     * @return
     */
    public BankcardResponseVO executeBankcardRequest(String imgStr) {
        String accessToken = this.getAccessToken();
        try {
            String param = "image=" + imgStr;
            String result = HttpUtil.post(domainName + "/rest/2.0/ocr/v1/bankcard", accessToken, param);
            log.info("请求百度ai返回数据：" + result);
            BankcardResponseVO bankcardResponseVO = JSONObject.parseObject(result, BankcardResponseVO.class);
            BankcardResponseVO.Result responseResult = bankcardResponseVO.getResult();
            if (0 == responseResult.getBank_card_type()) {
                throw new YnceErrorException("银行卡不能识别");
            }
            return bankcardResponseVO;
        } catch (Exception e) {
            throw new YnceErrorException(e.getMessage());
        }
    }
}
