package com.quantgroup.asset.distribution.service.funding.impl;

import cn.qg.ec.hbase.ocr.OCRIdCardDataService;
import cn.quantgroup.motan.bean.UserInfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lkb.data.hbase.row.verify.OCRIdCardRow;
import com.quantgroup.asset.distribution.constant.CodeConstants;
import com.quantgroup.asset.distribution.constant.aid.AidRiskInfoConstants;
import com.quantgroup.asset.distribution.constant.aid.PreAuditTypeConstants;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import com.quantgroup.asset.distribution.model.entity.OcrIdCardEntity;
import com.quantgroup.asset.distribution.model.entity.aid.*;
import com.quantgroup.asset.distribution.model.entity.live.FaceLiveEntity;
import com.quantgroup.asset.distribution.model.entity.live.TencentLiveEntity;
import com.quantgroup.asset.distribution.model.entity.user.SDKUserInfo;
import com.quantgroup.asset.distribution.model.entity.user.UserAddressInfo;
import com.quantgroup.asset.distribution.model.entity.user.UserContactInfo;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.model.response.MiddleOfficeResponse;
import com.quantgroup.asset.distribution.service.aid.IAidFundInfoConfigService;
import com.quantgroup.asset.distribution.service.feature.IFeatureService;
import com.quantgroup.asset.distribution.service.funding.IAidAssetCommonService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.jpa.entity.AidFundInfoConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.user.IUserCenterService;
import com.quantgroup.asset.distribution.util.MD5Util;
import com.quantgroup.asset.distribution.util.OcrUtils;
import com.quantgroup.asset.distribution.util.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author : Hyuk
 * @description : AidAssetCommonServiceImpl
 * @date : 2020/6/4 6:32 下午
 */
@Slf4j
@Service
public class AidAssetCommonServiceImpl implements IAidAssetCommonService {


    @Value("${opearotr.server.domain}")
    private String operatorDomain;

    @Autowired
    private IAidFundInfoConfigService aidFundInfoConfigService;
    @Autowired
    private IHttpService httpService;
    @Autowired
    private IUserCenterService userCenterService;
    @Autowired
    private IFeatureService featureService;

    @Override
    public boolean preAudit(AssetForm assetForm, String fundId, String fundProductId, Map<String, Object> data) {
        try {
            AidFundInfoConfig aidFundInfoConfig = aidFundInfoConfigService.findAidFundInfo(fundId, fundProductId);
            QGPreconditions.checkArgument(aidFundInfoConfig != null, QGExceptionType.AID_COMMON_FUND_CONFIG_IS_EMPTY, fundId, fundProductId);

            String preAuditUrl = aidFundInfoConfig.getPreAuditUrl();
            int preAuditType = aidFundInfoConfig.getPreAuditType().intValue();
            Map<String, String> requestParams = getPreAuditParams(assetForm.getUuid(), fundId, fundProductId, preAuditType);
            MiddleOfficeResponse response = request(preAuditUrl, aidFundInfoConfig.getFundId(), JSON.toJSONString(requestParams), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
            log.info("通用助贷资方预审完成, uuid : {}, bizNo : {}, bizType : {}, bizChannel : {}, fundId : {}, fundProductId : {}, response : {}",
                    assetForm.getUuid(), assetForm.getBizNo(), assetForm.getBizType(), assetForm.getBizChannel(), aidFundInfoConfig.getFundId(),
                    aidFundInfoConfig.getFundProductId(), JSON.toJSONString(response));

            if (CodeConstants.SUCCESS.equals(response.getCode())) {
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("助贷资方通用预审接口出现错误, uuid : {}, bizNo : {}, fundId : {}", assetForm.getUuid(), assetForm.getBizNo(), fundId, e);
            throw new QGException(QGExceptionType.AID_COMMON_PRE_AUDIT_ERROR, assetForm.getUuid(), assetForm.getBizNo(), fundId);
        }
    }

    @Override
    public boolean audit(AssetForm assetForm, Asset asset, Map<String, Object> data, String fundId, String fundProductId) {
        try {
            AidFundInfoConfig aidFundInfoConfig = aidFundInfoConfigService.findAidFundInfo(fundId, fundProductId);
            QGPreconditions.checkArgument(aidFundInfoConfig != null, QGExceptionType.AID_COMMON_FUND_CONFIG_IS_EMPTY, fundId, fundProductId);
            String requestURL = aidFundInfoConfig.getAuditUrl();

            // 用户中心相关信息, 这里不可能为空，不然预审就拦截住了
            UserInfo userInfo = userCenterService.getUserInfoByUuid(assetForm.getUuid());
            SDKUserInfo sdkUserInfo = userCenterService.getSDKUserExtInfo(userInfo.getPhoneNo(), assetForm.getUuid());
            QGPreconditions.checkArgument(sdkUserInfo != null, QGExceptionType.GET_USER_INFO_ERROR, assetForm.getUuid());

            AidIncomingEntity aidIncomingEntity = new AidIncomingEntity(assetForm.getBizNo());
            aidIncomingEntity.setUserInfo(createdAidUserInfo(userInfo, sdkUserInfo, assetForm.getUuid()));
            aidIncomingEntity.setContactsInfo(createdAidContactsInfo(sdkUserInfo.getContactList(), assetForm.getUuid()));
            aidIncomingEntity.setLoanInfo(createdAidLoanInfo(assetForm.getUuid()));
            aidIncomingEntity.setRiskInfo(createdAidRiskInfo(assetForm, data));

            MiddleOfficeResponse response = request(requestURL, aidFundInfoConfig.getFundId(), JSON.toJSONString(aidIncomingEntity), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
            log.info("通用助贷资方进件完成, uuid : {}, bizNo : {}, bizType : {}, bizChannel : {}, fundId : {}, fundProductId : {}, response : {}",
                    assetForm.getUuid(), assetForm.getBizNo(), assetForm.getBizType(), assetForm.getBizChannel(), aidFundInfoConfig.getFundId(),
                    aidFundInfoConfig.getFundProductId(), JSON.toJSONString(response));

            if (CodeConstants.SUCCESS.equals(response.getCode())) {
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("助贷资方通用进件接口出现错误, uuid : {}, bizNo : {}, fundId : {}", assetForm.getUuid(), assetForm.getBizNo(), fundId, e);
            throw new QGException(QGExceptionType.AID_COMMON_AUDIT_ERROR, assetForm.getUuid(), assetForm.getBizNo(), fundId);
        }

    }

    @Override
    public void auditResult(AssetForm assetForm, Asset asset, String fundId, String fundProductId) {
        try {
            AidFundInfoConfig aidFundInfoConfig = aidFundInfoConfigService.findAidFundInfo(fundId, fundProductId);
            QGPreconditions.checkArgument(aidFundInfoConfig != null, QGExceptionType.AID_COMMON_FUND_CONFIG_IS_EMPTY, fundId, fundProductId);

            Map<String, String> params = new HashMap<>();
            params.put("orderNo", assetForm.getBizNo());
            MiddleOfficeResponse response = request(aidFundInfoConfig.getAuditResultUrl(), aidFundInfoConfig.getFundId(), JSON.toJSONString(params), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
            log.info("助贷资方通用审核结果查询接口完成, uuid : {}, bizNo : {}, bizChannel : {}, bizType : {}, fundId : {}, fundProductId : {}, response : {}",
                    assetForm.getUuid(), assetForm.getBizNo(), assetForm.getBizChannel(), assetForm.getBizType(), fundId, fundProductId);

        } catch (Exception e) {
            log.error("助贷资方通用审核结果查询接口出现错误, uuid : {}, bizNo : {}, fundId : {}", assetForm.getUuid(), assetForm.getBizNo(), fundId);
            throw new QGException(QGExceptionType.AID_COMMON_QUERY_AUDIT_RESULT_ERROR, assetForm.getUuid(), assetForm.getBizNo(), fundId);
        }
    }

    /**
     * 获取撞库接口Map
     * @param uuid
     * @param fundId
     * @param fundProductId
     * @param preAuditType
     * @return
     */
    public Map<String, String> getPreAuditParams(String uuid, String fundId, String fundProductId, int preAuditType) {
        UserInfo userInfo = userCenterService.getUserInfoByUuid(uuid);
        if (userInfo == null){
            log.error("通用助贷资方推送获取用户中心信息失败 uuid : {}",uuid, fundId, fundProductId, preAuditType);
            throw new QGException(QGExceptionType.GET_USER_INFO_ERROR, uuid);
        }

        String name = userInfo.getName();
        String idNo = userInfo.getIdNo();
        String phoneNo = userInfo.getPhoneNo();
        if (StringUtils.isAnyEmpty(name, idNo, phoneNo)) {
            log.info("通用助贷资方推送，用户三要素部分缺失, fundId : {}, fundProductId : {}, uuid : {}");
            throw new QGException(QGExceptionType.GET_USER_INFO_ERROR, uuid);
        }

        Map<String, String> requestParams = new HashMap<>();
        requestParams.put("type", String.valueOf(preAuditType));
        switch (preAuditType) {
            case PreAuditTypeConstants.PHONE_NO_MD5 : {
                requestParams.put("phoneNo", MD5Util.md5(phoneNo));
                break;
            }
            case PreAuditTypeConstants.ID_CARD_MD5 : {
                requestParams.put("idCardNo", MD5Util.md5(idNo.replaceAll("x", "X")));
                break;
            }
            case PreAuditTypeConstants.PHONE_NO_ID_CARD_MD5 : {
                String param = phoneNo + idNo.replaceAll("x", "X");
                requestParams.put("exData", MD5Util.md5(param));
                break;
            }
            case PreAuditTypeConstants.PHONE_NO_OR_ID_CARD_NO_MD5 : {
                requestParams.put("phoneNo", MD5Util.md5(phoneNo));
                requestParams.put("idCardNo", MD5Util.md5(idNo.replaceAll("x", "X")));
                requestParams.put("name", name);
                break;
            }
            default:
                throw new QGException(QGExceptionType.UNKNOW_PRE_AUDIT_TYPE, fundId, preAuditType);
        }
        return requestParams;
    }

    /**
     * 创建助贷通用UserInfo
     * @param userInfo
     * @param sdkUserInfo
     * @param uuid
     * @return
     */
    private AidUserInfo createdAidUserInfo(UserInfo userInfo, SDKUserInfo sdkUserInfo, String uuid) {
        AidUserInfo aidUserInfo = new AidUserInfo();

        List<OCRIdCardRow> rows = OCRIdCardDataService.get(uuid);
        QGPreconditions.checkArgument(!CollectionUtils.isEmpty(rows), QGExceptionType.FUND_PRIORITY_IS_ERROR, uuid);
        OcrIdCardEntity ocrIdCardEntity = OcrUtils.transForm(rows.get(0));

        aidUserInfo.setName(ocrIdCardEntity.getIdCardA().getName());
        aidUserInfo.setIdCardNo(ocrIdCardEntity.getIdCardA().getCitizen_id().replaceAll("x", "X"));
        aidUserInfo.setPhoneNo(userInfo.getPhoneNo());

        // 教育程度
        String education = sdkUserInfo.getEducationEnum();
        aidUserInfo.setEducation("暂无".equals(education) ? "其他" : education);

        // 职业
        String occupation = sdkUserInfo.getOccupationEnum();
        aidUserInfo.setOccupation("暂未填写".equals(occupation) ? "其他" : occupation);

        // 收入
        String incomeRange = sdkUserInfo.getIncomeRangeEnum();
        aidUserInfo.setIncome("暂无".equals(incomeRange) ? "其他" : incomeRange);

        // 婚姻状况
        String maritalStatus = sdkUserInfo.getMarryStatus();
        aidUserInfo.setMaritalStatus("未知".equals(maritalStatus) ? "其他" : maritalStatus);

        UserAddressInfo addressInfo = sdkUserInfo.getAddressList().get(0);
        aidUserInfo.setAddress(addressInfo.getAddressDetail());
        aidUserInfo.setValidDateBegin(ocrIdCardEntity.getIdCardB().getValid_date_begin());
        aidUserInfo.setValidDateEnd(ocrIdCardEntity.getIdCardB().getValid_date_end());
        aidUserInfo.setIdCardAddress(ocrIdCardEntity.getIdCardA().getAddress());
        aidUserInfo.setGender("男".equals(ocrIdCardEntity.getIdCardA().getGender()) ? "1" : "2");
        aidUserInfo.setNation(ocrIdCardEntity.getIdCardA().getNation());
        aidUserInfo.setAgency(ocrIdCardEntity.getIdCardB().getAgency());
        aidUserInfo.setIdCardBaseContentA(ocrIdCardEntity.getIdCardBaseContentA());
        aidUserInfo.setIdCardBaseContentB(ocrIdCardEntity.getIdCardBaseContentB());
        aidUserInfo.setLivePhotoContent(ocrIdCardEntity.getLivePhotoContent());
        aidUserInfo.setEmail(sdkUserInfo.getEmail());

        // 0-腾讯 1-商汤 2-face++ 3-linkface
        int liveType = 0;
        TencentLiveEntity tencentLiveEntity = getTencentLiveEntity(uuid);
        if (tencentLiveEntity != null) {
            aidUserInfo.setLiveResult(tencentLiveEntity);
        } else {
            FaceLiveEntity faceLiveEntity = getFaceLiveEntity(uuid);
            if (faceLiveEntity != null) {
                liveType = 2;
                aidUserInfo.setLiveResult(faceLiveEntity);
            }
        }
        aidUserInfo.setLiveType(liveType);
        return aidUserInfo;
    }

    /**
     * 创建助贷通用联系人信息
     * @param uuid
     * @return
     */
    private AidContactsInfo createdAidContactsInfo(List<UserContactInfo> contactInfoList, String uuid) {
        QGPreconditions.checkArgument(!CollectionUtils.isEmpty(contactInfoList), QGExceptionType.USER_CONTACT_INFO_EMPTY, uuid);

        AidContactsInfo aidContactsInfo = new AidContactsInfo();
        aidContactsInfo.setFirstName(contactInfoList.get(0).getName());
        aidContactsInfo.setFirstMobile(contactInfoList.get(0).getPhoneNo());
        aidContactsInfo.setFirstRelation(contactInfoList.get(0).getRelationName());

        if (contactInfoList.size() > 1) {
            aidContactsInfo.setSecondName(contactInfoList.get(1).getName());
            aidContactsInfo.setSecondMobile(contactInfoList.get(1).getPhoneNo());
            aidContactsInfo.setSecondRelation(contactInfoList.get(1).getRelationName());
        }
        return aidContactsInfo;
    }

    /**
     * 创建助贷通用借款申请相关信息
     * @param uuid
     * @return
     */
    private AidLoanInfo createdAidLoanInfo(String uuid) {
        return null;
    }

    /**
     * 创建助贷通用风控信息
     * @param assetForm
     * @param data
     * @return
     */
    private AidRiskInfo createdAidRiskInfo(AssetForm assetForm, Map<String, Object> data) {
        String[] riskInfoKeys = {AidRiskInfoConstants.QG_SCORE3,
//                AidRiskInfoConstants.QG_SCORE5, AidRiskInfoConstants.QG_DEBT_PAYING_SCORE,
//                AidRiskInfoConstants.QG_RISK_LEVEL_PHONE, AidRiskInfoConstants.QG_RISK_LEVEL_IDNO
        };

        Set<String> keys = new HashSet<>();
        for (String riskInfoKey : riskInfoKeys) {
            if (data.get(riskInfoKey) == null) { keys.add(riskInfoKey); }
        }

        Map<String, Object> riskInfoData = featureService.getFeatureData(keys, assetForm, 1);
        data.putAll(riskInfoData);

        // 写死自然流量
        return AidRiskInfo.builder()
                .label(1)
                .qgScore3(data.get(AidRiskInfoConstants.QG_SCORE3))
//                .qgScore5(data.get(AidRiskInfoConstants.QG_SCORE5))
//                .qgDebtPayingScore(transformZhiShuConsumeLevel(data.get(AidRiskInfoConstants.QG_DEBT_PAYING_SCORE)))
//                .qgRiskLevelPhone(data.get(AidRiskInfoConstants.QG_RISK_LEVEL_PHONE))
//                .qgRiskLevelIdNo(data.get(AidRiskInfoConstants.QG_RISK_LEVEL_IDNO))
                .build();
    }

    /**
     * 获取腾讯活体结果
     * @param uuid
     * @return
     */
    private TencentLiveEntity getTencentLiveEntity(String uuid) {
        String url = operatorDomain + "/auth-center/ex/face/getOcrData.json";
        Map<String, String> params = new HashMap<>();
        params.put("uuid", uuid);
        // 以后增加活体类型记得增加枚举
        params.put("liveType", "teng_xun");

        String result = httpService.post(url, params);
        JSONObject data = JSON.parseObject(result);
        QGPreconditions.checkArgument(data != null , QGExceptionType.LIVE_DATA_ERROR, uuid);

        if ("0".equals(data.getString("code")) && "0".equals(data.getString("business_code"))) {
            return JSON.parseObject(data.getString("data"), TencentLiveEntity.class);
        }
        return null;
        // 这里为空抛一下异常, 理论上来说是不正常的, 因为都是自己的渠道, 之后增加其他活体类型, 再放到前筛里面去
//        throw new QGException(QGExceptionType.LIVE_DATA_ERROR, uuid);
    }

    /**
     * 获取Face活体
     * @param uuid
     * @return
     */
    private FaceLiveEntity getFaceLiveEntity(String uuid) {
        String url = operatorDomain + "/auth-center/ex/face/getOcrData.json";
        Map<String, String> params = new HashMap<>();
        params.put("uuid", uuid);
        // 以后增加活体类型记得增加枚举
        params.put("liveType", "face");

        String result = httpService.post(url, params);
        JSONObject data = JSON.parseObject(result);
        QGPreconditions.checkArgument(data != null , QGExceptionType.LIVE_DATA_ERROR, uuid);

        if ("0".equals(data.getString("code")) && "0".equals(data.getString("business_code"))) {
            return JSON.parseObject(data.getString("data"), FaceLiveEntity.class);
        }
        return null;
    }


    /**
     * 创建包装助贷资方对象
     * @param fundId
     * @param data
     * @param privateKey
     * @return
     */
    private String createRequestParams(String fundId, String data, String privateKey) throws Exception {
        AidRsaParams aidRsaParams = AidRsaParams.builder()
                                                .appId(fundId)
                                                .content(RsaUtils.encryptByPrivateKey(data, privateKey))
                                                .build();
        return JSON.toJSONString(aidRsaParams);
    }

    /**
     * 通用请求，包装加密和解密
     * @param url
     * @param fundId
     * @param data
     * @return
     */
    private MiddleOfficeResponse request(String url, String fundId, String data, String privateKey, String publicKey) throws Exception {
        String text = httpService.postJson(url, createRequestParams(fundId, data, privateKey));
        AidRsaParams aidRsaParams = JSON.parseObject(text, AidRsaParams.class);
        String result = RsaUtils.decryptByPublicKey(aidRsaParams.getContent(), publicKey);
        log.info("通用助贷资方请求结束, url : {}, data : {}, result : {}", url, data, result);
        MiddleOfficeResponse response = JSON.parseObject(result, MiddleOfficeResponse.class);
        return response;
    }

    /**
     * 智数数据结果转化
     * @param value
     * @return
     */
    public Object transformZhiShuConsumeLevel(Object value) {
        String valueStr = String.valueOf(value);
        if ("-9999999".equals(valueStr) || valueStr.startsWith("-99999")) {
            return 999;
        }
        if (valueStr.length() != 1) {
            throw new QGException(QGExceptionType.ZS_DATA_TRANSFORM_ERROR);
        }

        // 首先判断是否是数字
        if (StringUtils.isNumeric(valueStr)) {
            int valueInt = Integer.parseInt(valueStr);
            if (valueInt >= 0 && valueInt <= 9) {
                // 0-9 : 490-580
                return (valueInt - 0) * 10 + 490;
            } else {
                throw new QGException(QGExceptionType.ZS_DATA_TRANSFORM_ERROR);
            }
        } else {
            char charValue = valueStr.charAt(0);
            if (charValue >= 'A' && charValue <= 'Z') {
                if (charValue <= 'T') {
                    // 10-29层 ： 590-780
                    return ((int) charValue - (int) 'A') * 10 + 590;
                } else {
                    // 30-35层 : 790-795
                    return ((int)charValue - (int)'U') + 790;
                }
            } else if (charValue >= 'a' && charValue <= 'z') {
                if (charValue <= 'y') {
                    return ((int)charValue - (int)'a') + 796;
                } else {
                    return 999;
                }
            } else {
                throw new QGException(QGExceptionType.ZS_DATA_TRANSFORM_ERROR);
            }
        }
    }
}
