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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.quantgroup.asset.distribution.config.code.AreaCode;
import com.quantgroup.asset.distribution.config.code.InitAreaCode;
import com.quantgroup.asset.distribution.enums.route.SystemType;
import com.quantgroup.asset.distribution.model.entity.route.fundproduct.*;
import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundProductEntity;
import com.quantgroup.asset.distribution.service.jpa.entity.ProductRuleEntity;
import com.quantgroup.asset.distribution.service.jpa.entity.QFundProductEntity;
import com.quantgroup.asset.distribution.service.jpa.repository.IFundProductRepository;
import com.quantgroup.asset.distribution.service.jpa.repository.IProductRuleRepository;
import com.quantgroup.asset.distribution.service.newrule.pojo.funds.RuleParam;
import com.quantgroup.asset.distribution.service.route.IFundProductService;
import com.quantgroup.asset.distribution.util.AllRecords;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class FundProductServiceImpl implements IFundProductService {

    @Autowired
    private IFundProductRepository fundProductRepository;
    @Autowired
    private IProductRuleRepository productRuleRepository;


    @Autowired
    private IHttpService httpService;

    @Value("${mo-sidecar.http}")
    private String modsidecarurl;

    /**
     * 数据来源为QG底层资金运营服务，载入页面后，资金路由优先查询底层资金运营服务产品信息，再查询本地存储产品信息，然后进行去重展示；
     * @param fundProductQueryVo
     * @return
     */
    @Override
    public AllRecords queryPage(FundProductQueryVo fundProductQueryVo) {
        //1.资金路由优先查询底层资金运营服务产品信息
        List<FundProductEntity> fundProductFromMoFund = getFundProductFromMoFund();
        if (CollectionUtils.isEmpty(fundProductFromMoFund)){
            log.error("queryPage | 资金底层服务没有查到资金产品信息");
            return new AllRecords();
        }
        fundProductFromMoFund.stream().forEach(fundProductEntity -> {
            FundProductEntity byFundIdEqualsAndFundProIdEquals = fundProductRepository.getByFundIdEqualsAndFundProIdEquals(fundProductEntity.getFundId(), fundProductEntity.getFundProId());
            if (Objects.isNull(byFundIdEqualsAndFundProIdEquals)){
                fundProductEntity.setEnable(Byte.valueOf("1"));
                fundProductRepository.save(fundProductEntity);
            }
        });

        //2.查询本地数据库
        //索引 和 每页大小   排序   条件
        BooleanExpression booleanExpression = Expressions.asBoolean(true).isTrue();

        log.info("fundId={}",fundProductQueryVo.getFundId());
        if (Objects.nonNull(fundProductQueryVo.getFundId())){
            booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.fundId.like(fundProductQueryVo.getFundId() +"%"));
        }
        if (Objects.nonNull(fundProductQueryVo.getFundProId())){
            booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.fundProId.like(fundProductQueryVo.getFundProId() +"%"));
        }
        if (!StringUtils.isEmpty(fundProductQueryVo.getFundName())){
            booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.fundName.like(fundProductQueryVo.getFundName()+"%"));
        }
        if (!StringUtils.isEmpty(fundProductQueryVo.getFundType())){
            booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.fundType.eq(fundProductQueryVo.getFundType()));
        }
        if (!StringUtils.isEmpty(fundProductQueryVo.getOrgType())){
            booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.orgType.eq(fundProductQueryVo.getOrgType()));
        }
        if (!StringUtils.isEmpty(fundProductQueryVo.getBusinessType())){
            booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.businessType.eq(fundProductQueryVo.getBusinessType()));
        }
        if (!StringUtils.isEmpty(fundProductQueryVo.getSystermType())){
            booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.systermType.eq(fundProductQueryVo.getSystermType()));
        }
        //只查有效数据
        booleanExpression =  booleanExpression.and(QFundProductEntity.fundProductEntity.enable.eq(Byte.valueOf("1")));

        //1.查询条件，2.索引和每页的大小，3.排序根据某个字段进行排序
        //查询总条数
        long count = fundProductRepository.count(booleanExpression);
        //查询数据
        Page<FundProductEntity> plantPage = fundProductRepository.findAll(booleanExpression, new PageRequest(fundProductQueryVo.getPageIndex()-1, fundProductQueryVo.getPageSize(), new Sort(Sort.Direction.DESC, "updatedAt")));
        List<FundProductEntity> fundProductEntities = new ArrayList<>();
        fundProductEntities = plantPage.getContent();

        List<FundProductQueryResultVo> fundProductResultVos = new ArrayList<>();
        for (int i=0;i<fundProductEntities.size();i++){
            FundProductQueryResultVo fundProductResultVo = new FundProductQueryResultVo();
            BeanUtils.copyProperties(fundProductEntities.get(i), fundProductResultVo);
            fundProductResultVo.setSeqNo(fundProductEntities.size()-i);
            fundProductResultVos.add(fundProductResultVo);
        }

        AllRecords allRecords = new AllRecords();
        allRecords.setPageIndex(fundProductQueryVo.getPageIndex());
        allRecords.setPageSize(fundProductQueryVo.getPageSize());
        allRecords.setDataList(fundProductResultVos);
        allRecords.setTotalNumber(count);
        allRecords.resetTotalNumber(count);
        return allRecords;
    }

    private List<FundProductEntity> getFundProductFromMoFund(){
        List<FundProductEntity> fundProductEntityList = new ArrayList<>();
        String post = httpService.post(modsidecarurl + "/middle_office/financeProduct/infoList");
        if (Objects.nonNull(post) && JSON.parseObject(post).getInteger("code") == 0){
            JSONArray data = JSON.parseObject(post).getJSONArray("data");
            if (Objects.nonNull(data) && !data.isEmpty()){
                for (int i = 0 ; i< data.size() ;i++){
                    FundProductEntity fundProductEntity = new FundProductEntity();
                    fundProductEntity.setFundId(data.getJSONObject(i).getLong("fundCorpId"));
                    fundProductEntity.setFundProId(data.getJSONObject(i).getLong("financeProductId"));
                    fundProductEntity.setFundName(data.getJSONObject(i).getString("fundName"));
                    Integer systemNo = data.getJSONObject(i).getInteger("systemNo");
                    if (systemNo == 1){
                        fundProductEntity.setSystermType(SystemType.XYQB.getValue());
                    }else if (systemNo == 2){
                        fundProductEntity.setSystermType(SystemType.MO.getValue());
                    }
                    fundProductEntityList.add(fundProductEntity);
                }
            }
        }
        return fundProductEntityList;
    }

    @Override
    public FundProductVo lookFundProduct(Long id) {
        FundProductVo fundProductVo = new FundProductVo();
        FundProductEntity one = fundProductRepository.findOne(id);

        //1.资金信息-value
        BeanUtils.copyProperties(one,fundProductVo);
        //2.基本信息和其他信息字段
        //所有的BASIC规则
        List<ProductRuleEntity> basic = productRuleRepository.getAllByRuleTypeEqualsAndEnableEquals("BASIC", Byte.valueOf("1"));
        //所有的其他规则
        List<ProductRuleEntity> orther = productRuleRepository.getAllByRuleTypeEqualsAndEnableEquals("ORTHER", Byte.valueOf("1"));
        basic.addAll(orther);
        //3.基本信息和其他信息字段,对应的value
        Map<Long,String> map = new HashMap<>();
        //3.1解析基本规则10 <= age && age <= 50 && 10 <= amount && amount <= 20000 && (term == 12 || term == 10) && ! include(not_permit_tels,tel)
        //获取资金产品存的value
        String basicRule = one.getBasicRule();
        //解析value
        String[] split = basicRule.split("&&");
        for (String item : split) {
            for (ProductRuleEntity productRuleEntity : basic) {
                //在value中寻找对应的规则
                if ("not_permit_tels".equals(productRuleEntity.getRuleVal())) {
                    map.put(productRuleEntity.getId(), one.getTelRule());
                    break;
                }
                if (item.contains(productRuleEntity.getRuleVal())) {
                    if ("term".equals(productRuleEntity.getRuleVal())) {
                        String[] splitTerm = item.split("\\|\\|");
                        for (String value : splitTerm) {
                            //取出value中的值
                            String numeric = getNumeric(value);
                            String s = map.get(productRuleEntity.getId());
                            if (StringUtils.isEmpty(s)) {
                                map.put(productRuleEntity.getId(), numeric);
                            } else {
                                map.put(productRuleEntity.getId(), s.concat(",").concat(numeric));
                            }
                        }
                        break;
                    } else {
                        //取出value中的值
                        String numeric = getNumeric(item);
                        String s = map.get(productRuleEntity.getId());
                        if (StringUtils.isEmpty(s)) {
                            map.put(productRuleEntity.getId(), numeric);
                        } else {
                            map.put(productRuleEntity.getId(), s.concat(",").concat(numeric));
                        }
                        break;
                    }
                }
            }
        }
        //3.2基本规则剩下的字段
        //区域类型的规则
        String areaRule = one.getAreaRule();
        RuleParam.AreaRuleConcrete areaRuleConcrete = JSONObject.parseObject(areaRule, RuleParam.AreaRuleConcrete.class);
        //其它规则
        String ruleList = one.getRuleList();
        for (ProductRuleEntity productRuleEntity:basic){
            switch (productRuleEntity.getRuleVal()){
                case "area_term":
                    //地区要求
                    map.put(productRuleEntity.getId(),String.valueOf(one.getAreaTerm()));
                    break;
                case "card_limit":
                    //身份证有效期
                    map.put(productRuleEntity.getId(),String.valueOf(one.getCardLimit()));
                    break;
                case "tel_area_list":
                    //手机号区域限制
                    if (Objects.nonNull(areaRuleConcrete)){
                        try {
                            String telAreaCodeListByName = getTelAreaCodeListByName(areaRuleConcrete.getTelAreaNameList());
                            map.put(productRuleEntity.getId(),telAreaCodeListByName);
                        }catch (Exception e){
                            log.error("获取手机号区域限制异常",e);
                        }
                    }
                    break;
                case "residence_list":
                    //居住地区限制
                    if (Objects.nonNull(areaRuleConcrete)){
                        map.put(productRuleEntity.getId(),areaRuleConcrete.getResidenceList());
                    }
                    break;
                case "native_list":
                    //户籍地区限制（身份证）
                    if (Objects.nonNull(areaRuleConcrete)){
                        map.put(productRuleEntity.getId(),areaRuleConcrete.getNativeList());
                    }
                    break;
                case "name_same":
                case "tel_same":
                case "tel_no_same":
                    //联系人手机号不正确
                    //联系人手机号相同
                    //联系人姓名相同
                    map.put(productRuleEntity.getId(),ruleList.contains(String.valueOf(productRuleEntity.getId()))?"1":"0");
                    break;
            }
        }
        for (ProductRuleEntity productRuleEntity:basic){
            ProductRuleVo productRuleVo = new ProductRuleVo();
            BeanUtils.copyProperties(productRuleEntity,productRuleVo);
            productRuleVo.setValue(map.computeIfAbsent(productRuleEntity.getId(),k->""));
            if ("BASIC".equals(productRuleVo.getRuleType())){
                fundProductVo.getBasicRule().add(productRuleVo);
            }else if ("ORTHER".equals(productRuleVo.getRuleType())){
                fundProductVo.getOrtherRule().add(productRuleVo);
            }
        }
        return fundProductVo;
    }

    @Override
    public GlobalResponse save(FundProductSaveVo fundProductSaveVo) {
        FundProductEntity one = fundProductRepository.findOne(fundProductSaveVo.getId());
        if (Objects.isNull(one)){
            return GlobalResponse.error("没有这个资金产品");
        }
        BeanUtils.copyProperties(fundProductSaveVo,one);

        StringBuffer basicRule = new StringBuffer();
        StringBuffer ruleList = new StringBuffer();
        RuleParam.AreaRuleConcrete areaRuleConcrete = new RuleParam.AreaRuleConcrete();
        Map<Long, String> ruleValueMap = fundProductSaveVo.getRuleValueMap();
        List<ProductRuleEntity> allByEnableEquals = productRuleRepository.getAllByEnableEquals(Byte.valueOf("1"));
        allByEnableEquals.stream().forEach(productRuleEntity -> {
            String value = ruleValueMap.get(productRuleEntity.getId());
            if (!StringUtils.isEmpty(value)){
                //10 <= age && age <= 50 && 10 <= amount && amount <= 20000 && (term == 12 || term == 11) && ! include(not_permit_tels,tel)
                switch (productRuleEntity.getRuleVal()){
                    case "age":
                        basicRule.append(value.replace(",", " <= age && age <= ")).append(" && ");
                        break;
                    case "amount":
                        basicRule.append(value.replace(","," <= amount && amount <= ")).append(" && ");
                        break;
                    case "term":
                        basicRule.append("(");
                        String[] split = value.split(",");
                        for (int i = 0;i<split.length;i++){
                            basicRule.append("term == ").append(split[i]);
                            if (i != split.length-1){
                                basicRule.append(" || ");
                            }
                        }
                        basicRule.append(")").append(" && ");

                        //basicRule.append("term == ").append(value).append(" && ");
                        break;
                    case "not_permit_tels":
                        basicRule.append("! include(not_permit_tels,tel)").append(" && ");
                        one.setTelRule(value);
                        break;
                    case "name_same":
                    case "tel_same":
                    case "tel_no_same":
                        if ("1".equals(value)){
                            ruleList.append(productRuleEntity.getId()).append(",");
                        }
                        break;
                    case "area_term":
                        one.setAreaTerm(Integer.valueOf(value));
                        break;
                    case "card_limit":
                        one.setCardLimit(Integer.valueOf(value));
                        break;
                    case "tel_area_list":
                        try {
                            String telAreaNameListByCode = getTelAreaNameListByCode(value);
                            areaRuleConcrete.setTelAreaNameList(telAreaNameListByCode);
                        }catch (Exception e){
                            log.error("资金产品保存手机号区域限制异常",e);
                        }
                        break;
                    case "residence_list":
                        areaRuleConcrete.setResidenceList(value);
                        break;
                    case "native_list":
                        areaRuleConcrete.setNativeList(value);
                        break;
                }
            }
        });
        one.setBasicRule(basicRule.substring(0,basicRule.lastIndexOf(" && ")));

        if (!StringUtils.isEmpty(ruleList.toString())){
            one.setRuleList(ruleList.substring(0,ruleList.lastIndexOf(",")));
        }
        one.setAreaRule(JSONObject.toJSONString(areaRuleConcrete));
        fundProductRepository.save(one);
        return GlobalResponse.success();
    }

    //通过地区code获取对应的name
    private String getTelAreaNameListByCode(String value) throws IOException {
        if (StringUtils.isEmpty(value)){
            return "";
        }
        InputStream in = this.getClass().getResourceAsStream("/phone/gbt.txt");
        String var4 = InitAreaCode.getString(in);
        List<AreaCode> list = new ArrayList<AreaCode>();
        list = JSONObject.parseArray(var4, AreaCode.class);

        String replace = value.replace("[", "").replace("]", "");
        String[] split = replace.split(",");
        List<String> telAreaNameList = new ArrayList<>();
        for (int i = 0;i< split.length;i++){
            for (AreaCode areaCode:list){
                if (areaCode.getAdcode().equals(split[i])){
                    telAreaNameList.add(areaCode.getName());
                    break;
                }
            }
        }
        return telAreaNameList.toString();
    }

    //通过地区name获取对应的code
    private String getTelAreaCodeListByName(String value) throws IOException {
        if (StringUtils.isEmpty(value)){
            return "";
        }
        InputStream in = this.getClass().getResourceAsStream("/phone/gbt.txt");
        String var4 = InitAreaCode.getString(in);
        List<AreaCode> list = new ArrayList<AreaCode>();
        list = JSONObject.parseArray(var4, AreaCode.class);

        String replace = value.replace("[", "").replace("]", "");
        String[] split = replace.split(",");
        List<String> telAreaCodeList = new ArrayList<>();
        for (int i = 0;i< split.length;i++){
            for (AreaCode areaCode:list){
                if (areaCode.getName().equals(split[i])){
                    telAreaCodeList.add(areaCode.getAdcode());
                    break;
                }
            }
        }
        return telAreaCodeList.toString();
    }

    @Override
    public GlobalResponse getArea() throws IOException {
        AreaCodeVo areaCodeVo = new AreaCodeVo();

        InputStream in = this.getClass().getResourceAsStream("/phone/gbt.txt");
        String var4 = InitAreaCode.getString(in);
        List<AreaCode> list = new ArrayList<AreaCode>();
        list = JSONObject.parseArray(var4, AreaCode.class);

        for (AreaCode country : list) {
            if("100000".equals(country.getAdcode())){
                BeanUtils.copyProperties(country,areaCodeVo);
                //获取省
                for(AreaCode province : list){
                    if (country.getAdcode().equals(province.getParent())){
                        AreaCodeVo provinceVo = new AreaCodeVo();
                        BeanUtils.copyProperties(province,provinceVo);
                        //获取市
                        for (AreaCode city : list) {
                            if (province.getAdcode().equals(city.getParent())){
                                AreaCodeVo cityVo = new AreaCodeVo();
                                BeanUtils.copyProperties(city,cityVo);
                                //获取区
                                for (AreaCode district : list) {
                                    if (city.getAdcode().equals(district.getParent())){
                                        AreaCodeVo districtVo = new AreaCodeVo();
                                        BeanUtils.copyProperties(district,districtVo);
                                        cityVo.getNodes().add(districtVo);
                                    }
                                }
                                provinceVo.getNodes().add(cityVo);

                            }
                        }
                        areaCodeVo.getNodes().add(provinceVo);
                    }
                }
            }
        }

        return GlobalResponse.success(areaCodeVo);
    }

    /**
     * 过滤非数字
     * @param str
     * @return
     */
    public static String getNumeric(String str) {
        String regEx="[^0-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.replaceAll("").trim();
    }

}
