package digital.laboratory.platform.inspection.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import digital.laboratory.platform.common.core.util.R;
import digital.laboratory.platform.inspection.entity.*;
import digital.laboratory.platform.inspection.service.*;
import digital.laboratory.platform.inspetion.api.entity.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author xy
 * @version 1.0
 * @title IdentifyBookDataServiceImpl
 * @description
 * @create 2024/3/13 11:09
 */
@Service
@Slf4j
public class IdentifyBookDataServiceImpl implements IdentifyBookDataService {
    @Resource
    private TestRecordService testRecordService;//实验记录
    @Resource
    private EntrustInfoService entrustInfoService;//委托信息
    @Resource
    private SampleInfoService sampleInfoService;//检材信息
    @Resource
    private TestRecordSampleSolutionService testRecordSampleSolutionService;//样本溶液的service
    @Resource
    private TestRecordStandardSolutionService testRecordStandardSolutionService;//标准溶液的service
    @Resource
    private TestRecordSampleDataService testRecordSampleDataService;//检验数据
    @Resource
    private TestRecordMethodService testRecordMethodService;//检验方法

    /**
     * 获取完成实验的数据/获取符合制作文书的数据
     *
     * @return
     */
    @Override
    public R getTestFinishBusinessData(List<String> synedIdList) {
        List<EntrustInfo> entrustInfoList = entrustInfoService.list(Wrappers.<EntrustInfo>lambdaQuery()
                .ge(EntrustInfo::getStatus, 3)
                .notIn(CollectionUtils.isNotEmpty(synedIdList), EntrustInfo::getId, synedIdList));
        if (CollUtil.isNotEmpty(entrustInfoList)) {
            Map<String, List<SampleInfo>> sampleGroupByBusinessId = sampleInfoService
                    .list(Wrappers.<SampleInfo>lambdaQuery()
                            .in(SampleInfo::getBusinessId,
                                    entrustInfoList
                                            .stream()
                                            .map(EntrustInfo::getId)
                                            .collect(Collectors.toList())))
                    .stream()
                    .collect(Collectors.groupingBy(SampleInfo::getBusinessId));
            for (EntrustInfo entrustInfo : entrustInfoList) {
                List<SampleInfo> sampleInfos = sampleGroupByBusinessId.get(entrustInfo.getId());
                entrustInfo.setMaterialNum(sampleInfos.size());
            }
        }
        return R.ok(entrustInfoList, "获取数据成功");
    }

    /**
     * 获取文书的数据
     *
     * @param businessId
     * @return
     */
    @Override
    public IdentificationBookDTO getIdentifyBookDataByBusinessId(String businessId) {
        //一个委托案件，只能属于一个实验，不允许一个委托中的检材分配到2个实验中做实验，这个是前提
        if (ObjectUtils.isNotEmpty(businessId)) {
            IdentificationBookDTO identificationBookDTO = buildBookDataDetail(businessId);
            return identificationBookDTO;
        } else {
            log.info("参数业务id不能为空，请检查参数{}", businessId);
            return null;
        }
    }

    //构建文书数据
    private IdentificationBookDTO buildBookDataDetail(String businessId) {
        IdentificationBookDTO bookData = new IdentificationBookDTO();
        //委托信息
        EntrustInfo entrustInfo = entrustInfoService.getById(businessId);
        bookData.setEntrustInfo(entrustInfo);
        //检材
        List<SampleInfo> sampleList = sampleInfoService.list(Wrappers.<SampleInfo>lambdaQuery()
                .eq(SampleInfo::getBusinessId, businessId).orderByAsc(SampleInfo::getAcceptNo));
        bookData.setSampleInfoList(sampleList);

        //设置检验结果
        List<TestRecordSampleData> testRecordSampleDataList = getTestRecordSampleData(sampleList);//样本溶液对应的数据
        if (CollUtil.isEmpty(testRecordSampleDataList)) {
            return null;
        }
        List<TestResult> testResultsList = buildTestResult(testRecordSampleDataList, sampleList);//构建检验结果
        TestRecord testRecordInfo = testRecordService.lambdaQuery()
                .eq(TestRecord::getBusinessId, businessId)
                .one();
        //实验信息
        bookData.setTestMethod(getTestMethods(testRecordInfo));//设置用到的实验方法
        //设置检验过程
        bookData.setTestProcessDes(testRecordInfo.getTestProcessDes());//设置检验过程
        bookData.setTestResult(testRecordSampleDataService.generateQualitativeResults(businessId));
        //bookData.setTestResult(buildTestResultDes(testResultsList));//检验结果
        //检验日期

        DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        bookData.setTestStartDate(sdf.format(testRecordInfo.getCreateTime()));
        bookData.setTestOptUser(testRecordInfo.getTestUserId());
        bookData.setTestFinishDate(sdf.format(testRecordInfo.getUpdateTime()));
        return bookData;
    }

    //获取业务的实验对象
    private TestRecord getTestRecordInfo(List<TestRecordSampleSolution> testRecordSampleSolutionList) {
        List<String> testIdList = testRecordSampleSolutionList.stream().map(s -> s.getTestId()).collect(Collectors.toList());
        List<String> distinctTestId = testIdList.stream().distinct().collect(Collectors.toList());//去重复
        if (distinctTestId.size() != 1) {
            throw new RuntimeException("一个案件中的检材只能允许分配到一个实验中去做");
        }
        String testId = distinctTestId.get(0);
        TestRecord testRecord = testRecordService.getById(testId);
        return testRecord;
    }

    //获取实验方法
    private String getTestMethods(TestRecord testRecordInfo) {
        List<String> testMethodList = testRecordInfo.getTestMethodList();
        if (CollUtil.isEmpty(testMethodList)) {
            return "暂未找到实验过程中的方法数据!";
        }
        List<TestRecordMethod> methodsList = testRecordMethodService.list(Wrappers.<TestRecordMethod>lambdaQuery()
                .in(TestRecordMethod::getId, testMethodList));
        List<String> methodsName = methodsList.stream().map(s -> s.getMethodName()).collect(Collectors.toList());
        StringBuffer sbMethodNameStr = new StringBuffer();
        methodsName.forEach(item -> {
            sbMethodNameStr.append(item).append(",");
        });
        sbMethodNameStr.delete(sbMethodNameStr.length() - 1, sbMethodNameStr.length());
        return sbMethodNameStr.toString();
    }

    //获取sampleData
    private List<TestRecordSampleData> getTestRecordSampleData(List<SampleInfo> sampleInfoList) {
        if (CollUtil.isNotEmpty(sampleInfoList)) {
            List<String> sampleNoList = sampleInfoList.stream().map(m -> m.getAcceptNo()).collect(Collectors.toList());//得到样本溶液编号
            //根据样本溶液编号查出对应的样本溶液检验数据
            List<TestRecordSampleData> sampleTestDataList = getTestRecordData(sampleNoList);
            return sampleTestDataList;
        }

        return null;
    }

    //获取样本溶液
    private List<TestRecordSampleSolution> getTestRecordSampleSolution(List<SampleInfo> sampleInfoList) {
        List<String> materialIdList = sampleInfoList.stream().map(m -> m.getId()).collect(Collectors.toList());
        if (CollUtil.isEmpty(materialIdList)) {
            log.error("检材列表为空！");
            return null;
        }
        //查出对应的样本溶液
        List<TestRecordSampleSolution> sampleSolutionList = testRecordSampleSolutionService.list(Wrappers.<TestRecordSampleSolution>lambdaQuery()
                .in(TestRecordSampleSolution::getMaterialId, materialIdList));
        return sampleSolutionList;
    }

    //构建TestResult
    private List<TestResult> buildTestResult(List<TestRecordSampleData> testRecordSampleDataList,
                                             List<SampleInfo> sampleInfoList) {
        //结果：应该是加入实验的检材的结果，目前暂定受理的检材我们按照受理顺序，全部定义为 1号检材，2号检材，3号检材等
        //拿出实验数据中的所有实验样本编号，就是数据文件中的sampleId,也是溶液编号中的溶液编号，
        List<String> sampleNoList = testRecordSampleDataList.stream().map(s -> s.getSampleNo()).collect(Collectors.toList());

        List<TestResult> retTestResult = new ArrayList<>();
        Map<String, SampleInfo> sampleInfoMap = sampleInfoList
                .stream()
                .collect(Collectors.toMap(SampleInfo::getAcceptNo, Function.identity()));
        for (TestRecordSampleData testRecordSampleData : testRecordSampleDataList) {
            TestResult eg = new TestResult();
            SampleInfo sampleInfo = sampleInfoMap.get(testRecordSampleData.getSampleNo());
            eg.setCompoundName(testRecordSampleData.getCompoundName());
            eg.setMaterialNo(sampleInfo.getOrderNo() + "号");
            eg.setOrderNo(sampleInfo.getOrderNo());
            eg.setIsFind(testRecordSampleData.getIsDetected());
            eg.setTestId(testRecordSampleData.getTestId());
            retTestResult.add(eg);
        }
        return retTestResult;
    }

    //根据sampleID获取对应的检材信息
    private SampleInfo getSampleInfoBySampleId(List<TestRecordSampleSolution> testRecordSampleSolutionList,
                                               List<SampleInfo> sampleInfoList, String sampleId) {
        List<TestRecordSampleSolution> sampleSolutionList = testRecordSampleSolutionList.stream()
                .filter(s -> s.getSampleNo().equals(sampleId)).collect(Collectors.toList());
        String materialId = "";
        if (sampleSolutionList.size() > 0) {
            if (sampleSolutionList.size() > 1) {
                log.info("溶液编号重复 {} ", sampleId);
            } else {
                materialId = sampleSolutionList.get(0).getMaterialId();
            }
        }
        List<SampleInfo> retObj = new ArrayList<>();
        for (SampleInfo sampleInfo : sampleInfoList) {
            if (sampleInfo.getId().equals(materialId)) {
                //找到
                retObj.add(sampleInfo);
            }
        }
        if (retObj.size() != 1) {
            log.info("存在重复的检材");
            return null;
        }
        if (retObj.size() == 0) {
            log.info("未查询到检材");
            return null;
        } else {
            return retObj.get(0);
        }
    }

    //构建实验结果
    private List<String> buildTestResultDes(List<TestResult> resultList) {
        //按照检材编号先分组，这样的话，如果有n个检材，m个化合物，那么就会分成n组,每组中就m条数据
        Map<String, List<TestResult>> resultMap1 = resultList.stream().collect(Collectors.groupingBy(m -> m.getMaterialNo()));
        //我们把每组中的List 数据再次分组，分组按检出和未检出分，这样就会得到2个组，一个组是检出的，一个组是未检出的
        Map<String, Map<Integer, List<TestResult>>> resultMap2 = new HashMap<>();
        resultMap1.forEach((k, v) -> {
            //按检材编号分组，分成检出和未检出2组
            Map<Integer, List<TestResult>> tmp1Map = v.stream().collect(Collectors.groupingBy(m -> m.getIsFind()));
            resultMap2.put(k, tmp1Map);//1号  检出 与未检出
        });
        // 对 resultMap2进行合并，然后再次分组
        List<TestResultDetail> testResultDetailList = new ArrayList<>();
        resultMap2.forEach((k, v) -> {
            Map<Integer, List<TestResult>> tmp2Map = v;//这个map中只有2个key，key为0代表未检出的集合，key为1表示检出的集合
            TestResultDetail testResultDetail = buildCompoundList(tmp2Map, k);
            testResultDetailList.add(testResultDetail);
        });
        // 对 testResultDetailList 进行 分组
        //现在对上面的数据进行从新分组，按检出+化合物的形式
        Map<String, List<TestResultDetail>> temp2 = testResultDetailList.stream().collect(
                Collectors.groupingBy(m -> m.getFindCompounds() + m.getNoFindCompounds()));
        List<String> testResultDes = testResultSorted(temp2);
        return testResultDes;
    }

    //对第一个结果进行排序
    private List<String> testResultSorted(Map<String, List<TestResultDetail>> tmpMap) {
        List<Map.Entry<String, List<TestResultDetail>>> targetList = new ArrayList<Map.Entry<String, List<TestResultDetail>>>(tmpMap.entrySet());
        targetList.sort(new Comparator<Map.Entry<String, List<TestResultDetail>>>() {
            @Override
            public int compare(Map.Entry<String, List<TestResultDetail>> mp1, Map.Entry<String, List<TestResultDetail>> mp2) {
                int materialNo1 = getMinMaterialNo(mp1.getValue());
                int materialNo2 = getMinMaterialNo(mp2.getValue());
                return materialNo1 - materialNo2;
            }
        });
        List<String> testResultDes = new ArrayList<>();
        targetList.forEach((target) -> {
            StringBuffer sbNo = new StringBuffer();
            target.getValue().forEach(item -> {
                sbNo.append(item.getMaterialNo()).append(",");
            });
            if (sbNo.length() > 0) {
                sbNo.delete(sbNo.length() - 1, sbNo.length());//删除最后一个 ,
            }
            testResultDes.add(sbNo.toString() + "检材未检出" + target.getValue().get(0).getNoFindCompounds() + ",检出了" + target.getValue().get(0).getFindCompounds());
        });
        return testResultDes;
    }

    /**
     * 构造出一个检材一共检出了多少个化合物和未检出多少化合物
     *
     * @param mapCompound
     * @param materialNo
     * @return
     */
    private TestResultDetail buildCompoundList(Map<Integer, List<TestResult>> mapCompound, String materialNo) {

        StringBuffer findCompounds = new StringBuffer();//检出化合物的集合
        StringBuffer noFindCompounds = new StringBuffer();//未检出化合物的集合
        mapCompound.forEach((k1, v1) -> {
            if (k1 == 0) {
                //未检出
                v1.forEach(item -> {
                    noFindCompounds.append(item.getCompoundName()).append(",");
                });
            }
            if (k1 == 1) {
                //检出
                v1.forEach(item -> {
                    findCompounds.append(item.getCompoundName()).append(",");
                });
            }
        });
        if (findCompounds.length() > 0) {
            findCompounds.delete(findCompounds.length() - 1, findCompounds.length());//删除最后一个 ,
        }
        if (noFindCompounds.length() > 0) {
            noFindCompounds.delete(noFindCompounds.length() - 1, noFindCompounds.length());//删除最后一个 ,
        }
        TestResultDetail eg = new TestResultDetail();
        eg.setMaterialNo(materialNo);
        eg.setFindCompounds(findCompounds.toString());
        eg.setNoFindCompounds(noFindCompounds.toString());
        return eg;
    }

    private int getMinMaterialNo(List<TestResultDetail> materialList) {
        materialList.sort(new Comparator<TestResultDetail>() {
            @Override
            public int compare(TestResultDetail t1, TestResultDetail t2) {
                int mNo1 = Integer.parseInt(getNumberByMaterialNo(t1.getMaterialNo()));
                int mNo2 = Integer.parseInt(getNumberByMaterialNo(t2.getMaterialNo()));
                return mNo1 - mNo2;
            }
        });
        return Integer.parseInt(getNumberByMaterialNo(materialList.get(0).getMaterialNo()));
    }

    /**
     * 根据编号获取排序值
     *
     * @param materialNo
     * @return
     */
    private String getNumberByMaterialNo(String materialNo) {
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(materialNo);
        while (matcher.find()) {
            return matcher.group(0);
        }
        return "";
    }

    /**
     * 根据溶液编号(sampleNo)获取仪器检测数据
     *
     * @param sampleNoList
     * @return
     */
    private List<TestRecordSampleData> getTestRecordData(List<String> sampleNoList) {
        return testRecordSampleDataService.list(Wrappers.<TestRecordSampleData>lambdaQuery()
                .in(TestRecordSampleData::getSampleNo, sampleNoList));
    }
}
