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.google.common.base.Stopwatch;
import com.lkb.data.hbase.row.verify.OCRIdCardRow;
import com.quantgroup.asset.distribution.constant.AidFundStatus;
import com.quantgroup.asset.distribution.constant.aid.AidRiskInfoConstants;
import com.quantgroup.asset.distribution.enums.UserLoanType;
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.user.SDKUserInfo;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.feature.IFeatureService;
import com.quantgroup.asset.distribution.service.funding.*;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundAuditOrder;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundRouteRecord;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.redis.IRedisService;
import com.quantgroup.asset.distribution.service.rule.IRuleService;
import com.quantgroup.asset.distribution.service.user.IUserCenterService;
import com.quantgroup.asset.distribution.util.DateUtil;
import com.quantgroup.asset.distribution.util.OcrUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.AID_FUND_PUSH_ORDER_DAY_LIMIT_KEY;

/**
 * Created by renfeng on 2019/7/19.
 */
@Service
@Slf4j
public class AidFundRouteServiceImpl implements IAidFundRouteService {


    @Autowired
    private IAidLoanFundConfigService iAidLoanFundConfigService;
    @Autowired
    private IAidFundRouteRecordService iAidFundRouteRecordService;
    @Autowired
    private IRedisService<String> redisService;
    @Autowired
    private IRuleService ruleService;
    @Autowired
    private IAidFundAssetService aidFundAssetService;
    @Autowired
    private IAidFundAuditOrderService aidFundAuditOrderService;
    @Autowired
    private IFeatureService featureService;
    @Autowired
    private IUserCenterService userCenterService;


    /**
     * 助贷资金路由
     *
     * @param assetForm
     * @param asset
     * @param data
     * @return
     */
    @Override
    public boolean aidFundRoute(AssetForm assetForm, Asset asset, Map<String, Object> data) {


        Stopwatch started = Stopwatch.createStarted();
        //第一步 查询所有助贷资金
        List<AidLoanFundConfig> aidLoanFundConfigList = iAidLoanFundConfigService.findAll();
        log.info("助贷资金路由开始, uuid : {} , bizNo : {} ,助贷资金池 : {} ",assetForm.getUuid(),assetForm.getBizNo(),JSON.toJSONString(aidLoanFundConfigList));

        //第二步 开关筛选
        if(CollectionUtils.isNotEmpty(aidLoanFundConfigList))
            aidLoanFundConfigList = aidLoanFundConfigList.parallelStream().filter(aidLoanFundConfig->aidLoanFundConfig.getFundSwitchState()==1).collect(Collectors.toList());
//        //第三步 限制次数筛选, 改成按资方筛选
//        if(CollectionUtils.isNotEmpty(aidLoanFundConfigList)){
//            // AID_LOAN_COUNT_LIMIT_KEY + DateUtil.getDay() //TODO 放redis
//            aidLoanFundConfigList = aidLoanFundConfigList.parallelStream()
//                    .filter(aidLoanFundConfig->aidLoanFundConfig.getFundCountLimit() >=redisService.setIncr(AID_LOAN_COUNT_LIMIT_KEY + DateUtil.getDay(), 1, 3, TimeUnit.DAYS))
//                    .collect(Collectors.toList());
//        }
        //第四步 限制总额度筛选 额度筛选暂时没有用到
//        if(CollectionUtils.isNotEmpty(aidLoanFundConfigList)){
//            // 获取已放款总金额  AID_LOAN_ALL_AMOUNT_LIMIT_KEY + DateUtil.getDay() //TODO 放redis
//            String allAmount = redisService.getString(AID_LOAN_ALL_AMOUNT_LIMIT_KEY + DateUtil.getDay());
//            aidLoanFundConfigList = aidLoanFundConfigList.parallelStream()
//                    .filter(aidLoanFundConfig->new BigDecimal(aidLoanFundConfig.getFundAllAmountLimit()).compareTo(new BigDecimal(StringUtils.isEmpty(allAmount)?"0":allAmount))>0)
//                    .collect(Collectors.toList());
//        }
        //第五步 开始路由
        if(CollectionUtils.isNotEmpty(aidLoanFundConfigList)){

            log.info("助贷资金优先级筛选开始, uuid : {} , bizNo : {} ,助贷资金池 : {} ",assetForm.getUuid(),assetForm.getBizNo(),JSON.toJSONString(aidLoanFundConfigList));
            //按优先级排序
            TreeSet<AidLoanFundConfig> aidLoanFundConfigSet = new TreeSet<AidLoanFundConfig>(Comparator.comparing(AidLoanFundConfig::getFundPriority));
            aidLoanFundConfigSet.addAll(aidLoanFundConfigList);

            for(AidLoanFundConfig aidLoanFundConfig : aidLoanFundConfigSet){
                //此助贷资方如果已经被这笔订单路由过  就跳过
                AidLoanFundRouteRecord aidLoanFundRouteRecord = iAidFundRouteRecordService.findByBizNoAndFundId(assetForm.getBizNo(), aidLoanFundConfig.getFundId());
                int status = aidLoanFundRouteRecord == null ? -1 : aidLoanFundRouteRecord.getAidFundRouteStatus().intValue();
                if (status == AidFundStatus.Route.INCOMING_COMPLETE || status == AidFundStatus.Route.PRE_REJECT) {
                    // 进件完成和准入拒绝的直接跳过
                    continue;
                }
                //助贷资金分配规则校验
                if(ruleService.valid(aidLoanFundConfig.getFundRuleEl(), data)){
                    // 分配规则二次校验, md主要是风控的需求无法用表达式去满足, 特征值为null的居然让结果为true
                    if (!secondValid(data, aidLoanFundConfig, asset, assetForm)) { continue; }
                    // 助贷资金准入接口调用
                    boolean accessResult = false;
                    if (status == AidFundStatus.Route.PRE_PASS) {
                        accessResult = true;
                    } else {
                        // 调用次数限制
                        long increment = redisService.setIncr(AID_FUND_PUSH_ORDER_DAY_LIMIT_KEY + aidLoanFundConfig.getFundId() + ":" + DateUtil.getDay(), 1, 2, TimeUnit.DAYS);
                        if (increment > aidLoanFundConfig.getFundCountLimit()) {
                            redisService.setIncr(AID_FUND_PUSH_ORDER_DAY_LIMIT_KEY + aidLoanFundConfig.getFundId() + ":" + DateUtil.getDay(), -1, 2, TimeUnit.DAYS);
                            continue;
                        }

                        accessResult = aidFundAssetService.preAudit(assetForm, aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId(), data);
                        // 保存主贷资金路由记录
                        aidLoanFundRouteRecord = new AidLoanFundRouteRecord();
                        aidLoanFundRouteRecord.setAidFundRouteStatus(accessResult ? AidFundStatus.Route.PRE_PASS : AidFundStatus.Route.PRE_REJECT);//1-准入成功 2-准入失败 3-进件完成
                        aidLoanFundRouteRecord.setAssetNo(assetForm.getAssetNo());
                        aidLoanFundRouteRecord.setUuid(assetForm.getUuid());
                        aidLoanFundRouteRecord.setBizChannel(assetForm.getBizChannel());
                        aidLoanFundRouteRecord.setBizNo(assetForm.getBizNo());
                        aidLoanFundRouteRecord.setFinanceProductType(Integer.parseInt(assetForm.getBizType()));
                        aidLoanFundRouteRecord.setUserLoanType(asset.getUserLoanType());
                        aidLoanFundRouteRecord.setFundNo(aidLoanFundConfig.getFundNo());
                        aidLoanFundRouteRecord.setFundId(aidLoanFundConfig.getFundId());
                        aidLoanFundRouteRecord.setFundProductId(aidLoanFundConfig.getFundProductId());
                        aidLoanFundRouteRecord.setEnable(true);
                        aidLoanFundRouteRecord = iAidFundRouteRecordService.saveAidLoanFundRouteRecord(aidLoanFundRouteRecord);

                        log.info("助贷资金路由-准入完成, bizChannel : {} , uuid : {} , bizNo : {} , fundId : {} , fundProductId : {} , 准入结果 : {} , 耗时 : {}",assetForm.getBizChannel(),assetForm.getUuid(),assetForm.getBizNo(),aidLoanFundRouteRecord.getFundId(),aidLoanFundRouteRecord.getFundProductId(),accessResult,started.elapsed(TimeUnit.MILLISECONDS));
                    }

                    if(accessResult){
                        //客户类别区分 1-自然流量 2-拒绝流量   留在这里 你我贷暂时不用   等以后要用时 随时可用
//                        int customerType = 0 ;
//                        List<CustomerTypeRuleConfig> byEnableTrue = iCustomerTypeRuleConfigRepository.findByEnableTrue();
//                        if(CollectionUtils.isNotEmpty(byEnableTrue)) {
//                            for (CustomerTypeRuleConfig customerTypeRuleConfig : byEnableTrue) {
//                                if (ruleService.valid(customerTypeRuleConfig.getCustomerTypeRuleEl(), data)) {
//                                    customerType = customerTypeRuleConfig.getCustomerType();
//                                }
//                            }
//                        }
                        // 先创建进件订单记录
                        AidLoanFundAuditOrder aidLoanFundAuditOrder = createAidFundAuditOrder(aidLoanFundRouteRecord, assetForm, asset, data);
                        // 调用助贷资方进件接口 异步
                        boolean incomingResult = aidFundAssetService.audit(assetForm, data, asset, aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId());
                        // 将助贷路由记录状态改为进件完成
                        iAidFundRouteRecordService.updateAidLoanFundRouteRecordStatus(aidLoanFundRouteRecord, AidFundStatus.Route.INCOMING_COMPLETE);
                        log.info("助贷资金路由-进件完成, bizChannel : {} , uuid : {} , bizNo : {} , fundId : {} , fundProductId : {} , 进件结果 : {}, 耗时 : {} ",assetForm.getBizChannel(),assetForm.getUuid(),assetForm.getBizNo(),aidLoanFundRouteRecord.getFundId(),aidLoanFundRouteRecord.getFundProductId(),incomingResult,started.stop().elapsed(TimeUnit.MILLISECONDS));

                        if (incomingResult) {
                            aidFundAuditOrderService.updateOrderStatus(aidLoanFundAuditOrder, AidFundStatus.Incoming.WAIT);
                            return true;
                        } else {
                            aidFundAuditOrderService.updateOrderStatus(aidLoanFundAuditOrder, AidFundStatus.Incoming.REJECT);
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * 创建资方审核订单
     * @param aidLoanFundRouteRecord
     * @param assetForm
     * @param asset
     * @param data
     */
    private AidLoanFundAuditOrder createAidFundAuditOrder(AidLoanFundRouteRecord aidLoanFundRouteRecord, AssetForm assetForm, Asset asset, Map<String, Object> data) {
        AidLoanFundAuditOrder aidLoanFundAuditOrder = aidFundAuditOrderService.findByBizNoAndFundId(assetForm.getBizNo(), aidLoanFundRouteRecord.getFundId());
        if (aidLoanFundAuditOrder != null) {
            log.info("助贷资方审核订单已存在, 直接返回订单, uuid : {}, bizNo : {}, assetNo : {}, bizChannel : {}, orderStatus : {}", assetForm.getUuid(), assetForm.getBizNo(),
                    assetForm.getAssetNo(), assetForm.getBizChannel(), aidLoanFundAuditOrder.getAuditResult());
            return aidLoanFundAuditOrder;
        }
        aidLoanFundAuditOrder = new AidLoanFundAuditOrder();
        aidLoanFundAuditOrder.setAssetNo(asset.getAssetNo());
        aidLoanFundAuditOrder.setFundNo(aidLoanFundRouteRecord.getFundNo());
        aidLoanFundAuditOrder.setUuid(assetForm.getUuid());
        aidLoanFundAuditOrder.setBizNo(assetForm.getBizNo());
        aidLoanFundAuditOrder.setFundId(aidLoanFundRouteRecord.getFundId());
        aidLoanFundAuditOrder.setFundProductId(aidLoanFundRouteRecord.getFundProductId());
        aidLoanFundAuditOrder.setAssetFormText(JSON.toJSONString(assetForm));
        aidLoanFundAuditOrder.setAssetText(JSON.toJSONString(asset));
        aidLoanFundAuditOrder.setDataText(JSON.toJSONString(data));
        aidLoanFundAuditOrder.setAuditResult(AidFundStatus.Incoming.PRE);
        aidLoanFundAuditOrder.setEnable(true);
        return aidFundAuditOrderService.saveAidFundAuditOrder(aidLoanFundAuditOrder);
    }

    /**
     * 助贷分配规则二次校验
     * 一次校验的时候已经限制了渠道号, 这里就不需要了
     * @param data
     * @param aidLoanFundConfig
     * @param asset
     * @param assetForm
     * @return
     */
    private boolean secondValid(Map<String, Object> data, AidLoanFundConfig aidLoanFundConfig, Asset asset, AssetForm assetForm) {
        boolean valid = true;
        if ("970".equals(aidLoanFundConfig.getFundId()) && "1052".equals(aidLoanFundConfig.getFundProductId())) {
            // 你我贷助贷资方
            QGPreconditions.checkArgument(asset.getUserLoanType() != null, QGExceptionType.USER_LOAN_TYPE_IS_EMPTY, asset.getUuid());
            if (asset.getUserLoanType() == UserLoanType.FIRST_APPLY.getCode() || asset.getUserLoanType() == UserLoanType.RE_APPLY.getCode()) {
                // 同盾分拒绝的不推
                if (data.get("model_exec_data_source#tongdun_v2_1_bucket") != null) {
                    Integer tongdun_v2_1_bucket = Integer.parseInt(String.valueOf(data.get("model_exec_data_source#tongdun_v2_1_bucket")));
                    if (tongdun_v2_1_bucket != null && (tongdun_v2_1_bucket < 1 || tongdun_v2_1_bucket > 185)) {
                        log.info("助贷资方导流, 用户命中二次校验规则, 不进行导流, uuid : {}, fundId : {}, fundProId : {}, tongdunScore : {}",
                                asset.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId(), tongdun_v2_1_bucket);
                        return false;
                    }
                }
            }
        } else if ("1050".equals(aidLoanFundConfig.getFundId()) && "1062".equals(aidLoanFundConfig.getFundProductId())) {
            // 新橙
            // 1、年龄22-55限制
            Integer age = (Integer)data.get("user_age");
            if (age == null || age.intValue() < 22 || age.intValue() > 55) {
                valid = false;
            }
            // 2、新疆、青海、西藏、福建不导
            String province = (String)data.get("user_province_code");
            if (province == null || "65".equals(province) || "63".equals(province) || "54".equals(province) || "35".equals(province)) {
                valid = false;
            }

            // 这里提前走, 节省数据费用
            if (!valid) {
                log.info("助贷资方导流, 用户命中二次校验规则, 不进行导流, uuid : {}, fundId : {}, fundProductId : {}, userAge : {}, province : {}",
                        asset.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId(), age, province);
                return valid;
            }


            // 3、量子分3缺失的不导
            if (data.get(AidRiskInfoConstants.QG_SCORE3) == null) {
                Set<String> keys = new HashSet<>();
                keys.add(AidRiskInfoConstants.QG_SCORE3);
                Map<String, Object> features = featureService.getFeatureData(keys, assetForm, 1);
                data.putAll(features);
            }
            String qgScore3 = String.valueOf(data.get(AidRiskInfoConstants.QG_SCORE3));
            if (qgScore3 == null || qgScore3.startsWith("-999999") || "9999999".equals(qgScore3)) {
                valid = false;
            }

            if (!valid) {
                log.info("助贷资方导流, 用户命中二次校验规则, 不进行导流, uuid : {}, fundId : {}, fundProductId : {}, userAge : {}, province : {}, qgScore3 : {}",
                        asset.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId(), age, province, qgScore3);
            }
        }

        if (!valid) { return false; }

        // 通用, 用户联系人缺失的不导, md，这是用户中心的bug, 要在这里做兼容
        UserInfo userInfo = userCenterService.getUserInfoByUuid(assetForm.getUuid());
        if (userInfo == null || StringUtils.isEmpty(userInfo.getPhoneNo())) {
            log.info("助贷资方导流, 用户手机号缺失, 不进行导流, uuid : {}, fundId : {}, fundProductId : {}", asset.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId());
            return false;
        }

        SDKUserInfo sdkUserInfo = userCenterService.getSDKUserExtInfo(userInfo.getPhoneNo(), assetForm.getUuid());
        if (sdkUserInfo == null || sdkUserInfo.getContactList() == null || sdkUserInfo.getContactList().size() == 0 ||
            sdkUserInfo.getAddressList() == null || sdkUserInfo.getAddressList().size() == 0) {
            log.info("助贷资方导流, 用户联系人缺失, 不进行导流, uuid : {}, fundId : {}, fundProductId : {}, contactList : {}, addressList : {}",
                    assetForm.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId(), 0, 0);
            return false;
        }

        // OCR,活体照片缺失不导, 兼容融3自动2推缺失ocr、活体情况
        List<OCRIdCardRow> rows = OCRIdCardDataService.get(assetForm.getUuid());
        if (org.springframework.util.CollectionUtils.isEmpty(rows)) {
            log.info("助贷资方导流, 用户ocr活体信息缺失, 不进行导流, uuid : {}, fundId : {}, fundProductId : {}",
                    assetForm.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId());
            return false;
        }
        OcrIdCardEntity ocrIdCardEntity = OcrUtils.transForm(rows.get(0));
        if (Objects.isNull(ocrIdCardEntity.getIdCardA()) || Objects.isNull(ocrIdCardEntity.getIdCardB()) ||
            StringUtils.isAnyEmpty(ocrIdCardEntity.getIdCardBaseContentA(), ocrIdCardEntity.getIdCardBaseContentB(), ocrIdCardEntity.getLivePhotoContent())) {

            log.info("助贷资方导流, 用户ocr活体信息缺失, 不进行导流, uuid : {}, fundId : {}, fundProductId : {}",
                    assetForm.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId());
            return false;
        }

        return true;
    }
}
