package com.yeejoin.amos.api.openapi.face.service;


import com.yeejoin.amos.api.openapi.constant.*;
import com.yeejoin.amos.api.openapi.face.model.*;
import com.yeejoin.amos.api.openapi.face.orm.dao.RegistrationInfoMapper;
import com.yeejoin.amos.api.openapi.face.orm.entity.RegistrationInfo;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * 气瓶数据校验
 */
@Component
public class CylinderFillingDataValidationService {

    @Autowired
    EnterpriseInfoService enterpriseInfoService;
    @Autowired
    RegistrationInfoMapper registrationInfoMapper;

    /**
     * 企业信息校验
     * @param unitData
     * @return
     */
    public boolean validatEcylinderUnit(List<CylinderUnitModel> unitData) {
        JSONArray jsonArray = JSONArray.fromObject(unitData);
        List<String> keys = Arrays.stream(CylinderUnitFieldEnum.values()).map(e -> e.name()).collect(Collectors.toList());
        // 1.必填校验
        List<String> errorRows = validateRequired(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            throw new BadRequest(JSONArray.fromObject( errorRows.stream().map(e -> "必填字段为空：：" + e).collect(Collectors.toList())).toString());
        }
        // 2.本次上传数据唯一性校验
        errorRows = validateUnique(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            throw new BadRequest(JSONArray.fromObject( errorRows.stream().map(e -> "上传数据重复：" + e).collect(Collectors.toList())).toString());
        }
        // 3.检查企业统一社会信用代码是否存在
        Set<String> creditCodes = getAllData(FillingBeforeFieldEnum.creditCode.name(), jsonArray);
        errorRows = getNotExistEnterpriseInfoByCreditCode(creditCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            throw new BadRequest(JSONArray.fromObject(errorRows.stream().map(e -> "企业统一社会信用代码不存在：" + e).collect(Collectors.toList())).toString());
        }
        return true;
    }


    public boolean validateCylinderInfo(List<CylinderInfoModel> infoData) {
        JSONArray jsonArray = JSONArray.fromObject(infoData);
        List<String> keys = Arrays.stream(CylinderInfoFieldEnum.values()).map(e -> e.name()).collect(Collectors.toList());
        // 1.必填校验
        List<String> errorRows = validateRequired(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            throw new BadRequest(JSONArray.fromObject( errorRows.stream().map(e -> "必填字段为空：：" + e).collect(Collectors.toList())).toString());
        }
        // 2.本次上传数据唯一性校验
        errorRows = validateUnique(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            throw new BadRequest(JSONArray.fromObject(  errorRows.stream().map(e -> "上传数据重复：" + e).collect(Collectors.toList())).toString());
        }
        // 3.检查气瓶唯一标识码是否存在
        Set<String> sequenceCodes = getAllData(FillingBeforeFieldEnum.sequenceCode.name(), jsonArray);
        errorRows = getNotExistSequenceCodes(sequenceCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            throw new BadRequest(JSONArray.fromObject(  errorRows.stream().map(e -> "气瓶唯一标识码不存在：" + e).collect(Collectors.toList())).toString());
        }
        // 4.检查企业统一社会信用代码是否存在
        Set<String> creditCodes = getAllData(FillingBeforeFieldEnum.creditCode.name(), jsonArray);
        errorRows = getNotExistEnterpriseInfoByCreditCode(creditCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            throw new BadRequest(JSONArray.fromObject(  errorRows.stream().map(e -> "企业统一社会信用代码不存在：" + e).collect(Collectors.toList())).toString());
        }
        return true;
    }

    /**
     * 验证气瓶充装数据
     * @return
     */
    public CylinderFillingDataValidationResultModel validateFilling(JSONObject jsonobject) throws ExecutionException, InterruptedException {
        CylinderFillingDataValidationResultModel result = new CylinderFillingDataValidationResultModel();
        CompletableFuture<List<String>> beforeFuture = CompletableFuture.supplyAsync(() -> {
            // 异步校验检验前数据
            return validateFillingBeforeData(jsonobject.getJSONArray("fillingBefore"));
        });
        CompletableFuture<List<String>> recordFuture = CompletableFuture.supplyAsync(() -> {
            //  异步校验检填充数据
            return validateFillingRecordData(jsonobject.getJSONArray("filling"));
        });

        CompletableFuture<List<String>> afterFuture = CompletableFuture.supplyAsync(() -> {
            // 异步校验检填充后数据
            return validateFillinAfterData(jsonobject.getJSONArray("fillingAfter"));
        });

        /**
         * 等待校验结果
         */
        CompletableFuture.allOf(beforeFuture, recordFuture, afterFuture);
        result.setBeforeErrorData(beforeFuture.get());
        result.setRecordErrorData(recordFuture.get());
        result.setAfterErrorData(afterFuture.get());
        return result;
    }


    /**
     * 验证检验前数据
     * @param jsonArray
     * @return List 异常数据
     */
    public List<String> validateFillingBeforeData(JSONArray jsonArray) {
        List<String> keys = Arrays.stream(FillingBeforeFieldEnum.values()).map(e -> e.name()).collect(Collectors.toList());
        // 1.必填校验
        List<String> errorRows = validateRequired(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "必填字段为空：：" + e).collect(Collectors.toList());
        }
        // 2.本次上传数据唯一性校验
        errorRows = validateUnique(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "上传数据重复：" + e).collect(Collectors.toList());
        }
        // 3.检查气瓶唯一标识码是否存在
        Set<String> sequenceCodes = getAllData(FillingBeforeFieldEnum.sequenceCode.name(), jsonArray);
        errorRows = getNotExistSequenceCodes(sequenceCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "气瓶唯一标识码不存在：" + e).collect(Collectors.toList());
        }
        // 4.检查企业统一社会信用代码是否存在
        Set<String> creditCodes = getAllData(FillingBeforeFieldEnum.creditCode.name(), jsonArray);
        errorRows = getNotExistEnterpriseInfoByCreditCode(creditCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "企业统一社会信用代码不存在：" + e).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 验证检验记录数据
     * @param jsonArray
     * @return List 异常数据
     */
    public List<String> validateFillingRecordData(JSONArray jsonArray) {
        List<String> keys = Arrays.stream(FillingRecordFieldEnum.values()).map(e -> e.name()).collect(Collectors.toList());
        // 1.必填校验
        List<String> errorRows = validateRequired(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "必填字段为空：：" + e).collect(Collectors.toList());
        }
        // 2.本次上传数据唯一性校验
        errorRows = validateUnique(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "上传数据重复：" + e).collect(Collectors.toList());
        }
        // 3.检查气瓶唯一标识码是否存在
        Set<String> sequenceCodes = getAllData(FillingBeforeFieldEnum.sequenceCode.name(), jsonArray);
        errorRows = getNotExistSequenceCodes(sequenceCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "气瓶唯一标识码不存在：" + e).collect(Collectors.toList());
        }
        // 4.检查企业统一社会信用代码是否存在
        Set<String> creditCodes = getAllData(FillingBeforeFieldEnum.creditCode.name(), jsonArray);
        errorRows = getNotExistEnterpriseInfoByCreditCode(creditCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "企业统一社会信用代码不存在：" + e).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 验证检验后数据
     * @param jsonArray
     * @return List 异常数据
     */
    public List<String> validateFillinAfterData(JSONArray jsonArray) {
        List<String> keys = Arrays.stream(FillingAfterFieldEnum.values()).map(e -> e.name()).collect(Collectors.toList());
        // 1.必填校验
        List<String> errorRows = validateRequired(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "必填字段为空：：" + e).collect(Collectors.toList());
        }
        // 2.本次上传数据唯一性校验
        errorRows = validateUnique(keys, jsonArray);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "上传数据重复：" + e).collect(Collectors.toList());
        }
        // 3.检查气瓶唯一标识码是否存在
        Set<String> sequenceCodes = getAllData(FillingBeforeFieldEnum.sequenceCode.name(), jsonArray);
        errorRows = getNotExistSequenceCodes(sequenceCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "气瓶唯一标识码不存在：" + e).collect(Collectors.toList());
        }
        // 4.检查企业统一社会信用代码是否存在
        Set<String> creditCodes = getAllData(FillingBeforeFieldEnum.creditCode.name(), jsonArray);
        errorRows = getNotExistEnterpriseInfoByCreditCode(creditCodes);
        if (!ObjectUtils.isEmpty(errorRows)) {
            return errorRows.stream().map(e -> "企业统一社会信用代码不存在：" + e).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 必填校验
     * @param keys 需要校验的key
     * @param jsonArray 被校验数据
     * @return 校验结果 通过为 true，不通过为false
     */
    public List<String> validateRequired(List<String> keys, JSONArray jsonArray) {
        List<String> errorList = new ArrayList<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject row = jsonArray.getJSONObject(i);
            for (String key : keys) {
                if (!row.containsKey(key) || row.get(key) == null) {
                    errorList.add(row.toString());
                }
            }
        }

        return errorList;
    }

    /**
     * 数据唯一性校验
     * @param keys 需要校验的key
     * @param jsonArray 被校验数据
     * @return 校验结果 通过为 true，不通过为false
     */
    public List<String> validateUnique(List<String> keys, JSONArray jsonArray) {
        Map<String, Set<Object>> valuesMap = new HashMap<>();
        List<String> errorList = new ArrayList<>();
        for (String key : keys) {
            valuesMap.put(key, new HashSet<>());
        }
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject row = jsonArray.getJSONObject(i);
            for (String key : keys) {
                if (valuesMap.get(key).contains(row.get(key))) {
                    errorList.add(row.toString());
                }
                valuesMap.get(key).add(row.get(key));
            }
        }

        return errorList;
    }

    /**
     * 获取指定 key的所有数据
     * @param key
     * @param jsonArray
     * @return
     */
    public Set<String> getAllData(String key, JSONArray jsonArray) {
        Set<String> sequenceCode = new HashSet<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject row = jsonArray.getJSONObject(i);
            sequenceCode.add(row.get(key).toString());
        }
        return sequenceCode;
    }

    /**
     * 校验企业唯一信用代码
     * @param creditCodes
     * @return
     */
    public List<String> getNotExistEnterpriseInfoByCreditCode(Set<String> creditCodes) {
        List<EnterpriseInfoModel> enterpriseInfos = enterpriseInfoService.getEnterpriseInfoByCreditCode(creditCodes);
        if (enterpriseInfos.size() < creditCodes.size()) {
            List<String> userCodes = enterpriseInfos.stream().map(e -> e.getUseCode()).collect(Collectors.toList());
            return creditCodes.stream().filter(c -> !userCodes.contains(c)).collect(Collectors.toList());
        }
        return null;
    }

    /**
     *  获取不存在的气瓶编码
     * @param sequenceCodes
     * @return
     */
    public List<String> getNotExistSequenceCodes(Set<String> sequenceCodes) {
        List<RegistrationInfo> useInfos = registrationInfoMapper.getUseInfoByEquipCode(sequenceCodes);
        if (useInfos.size() < sequenceCodes.size()) {
            List<String> equipCodes = useInfos.stream().map(e -> e.getEquCode()).collect(Collectors.toList());
            return sequenceCodes.stream().filter(c -> !equipCodes.contains(c)).collect(Collectors.toList());
        }
        return null;
    }
}
