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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import digital.laboratory.platform.inspection.constant.TestRecordSampleDataConstant;
import digital.laboratory.platform.inspection.convert.TestSampleDataExpandConverter;
import digital.laboratory.platform.inspection.dto.HairSewageDataDto;
import digital.laboratory.platform.inspection.dto.NPSCaseTestDataDto;
import digital.laboratory.platform.inspection.dto.TestSampleDataExpandDTO;
import digital.laboratory.platform.inspection.entity.TestRecordSampleData;
import digital.laboratory.platform.inspection.entity.TestRecordSampleDataExpand;
import digital.laboratory.platform.inspetion.api.enums.BusinessType;
import digital.laboratory.platform.inspection.mapper.TestRecordSampleDataExpandMapper;
import digital.laboratory.platform.inspection.service.ProcessInspectDataService;
import digital.laboratory.platform.inspection.service.TestRecordSampleDataService;
import digital.laboratory.platform.inspection.service.TestRecordSampledataExpandService;
import digital.laboratory.platform.inspection.service.TestRecordService;
import digital.laboratory.platform.inspection.utils.datafile.nps.NPSTestDetailDataStruct;
import digital.laboratory.platform.inspetion.api.entity.TestRecord;
import digital.laboratory.platform.sys.entity.Drug;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ChenJiangBao
 * @description 针对表【b_test_record_sampledata_expand(样本检验数据的扩展信息)】的数据库操作Service实现
 * @createDate 2025-03-19 14:58:17
 */
@Slf4j
@Service
public class TestRecordSampledataExpandServiceImpl extends ServiceImpl<TestRecordSampleDataExpandMapper, TestRecordSampleDataExpand>
        implements TestRecordSampledataExpandService {

    @Resource
    private TestRecordService testRecordService;

    @Resource
    private TestRecordSampleDataService testRecordSampleDataService;

    @Resource
    private ProcessInspectDataService processInspectDataService;

    /**
     * 封装处理毛发案件、任务等检验扩展数据信息
     *
     * @param hairSewageDataDto
     * @param testDataId
     * @return
     */
    public Collection<? extends TestRecordSampleDataExpand> saveHairSewageInspectExpData(HairSewageDataDto hairSewageDataDto, String testDataId) {
        List<TestRecordSampleDataExpand> hairSewageInspectExpDataList = new ArrayList<>();

        // 设置基峰的扩展数据
        if (!TestRecordSampleDataConstant.isInvalidValue(hairSewageDataDto.getPeakAreaUp())) {
            hairSewageInspectExpDataList.add(createTestRecordSampleDataExpand(testDataId, Boolean.TRUE,
                    hairSewageDataDto.getPeakAreaUp(), null, null, null, null, null, hairSewageDataDto.getQualitativeIonPairUp(), null));
        }

        if (!TestRecordSampleDataConstant.isInvalidValue(hairSewageDataDto.getPeakAreaDown())) {
            hairSewageInspectExpDataList.add(createTestRecordSampleDataExpand(testDataId, Boolean.FALSE,
                    hairSewageDataDto.getPeakAreaDown(), hairSewageDataDto.getIonAbundanceRatio(),
                    hairSewageDataDto.getIonAbundanceRatioWithinError(), hairSewageDataDto.getWhetherCheckOut(), null, null, hairSewageDataDto.getQualitativeIonPairDown(), null));
        }

        return hairSewageInspectExpDataList;
    }

    /**
     * 封装处理nps案件检验扩展数据信息
     *
     * @param npsCaseTestDataDto
     * @param testDataId
     * @return
     */
    @Override
    public Collection<? extends TestRecordSampleDataExpand> saveNPSInspectExpData(NPSCaseTestDataDto npsCaseTestDataDto, String testDataId) {
        // 检验数据
        List<NPSTestDetailDataStruct> npsTestSampleDataList = npsCaseTestDataDto.getTestSampleDataList();

        List<TestRecordSampleDataExpand> testRecordSampleDataExpandList = npsTestSampleDataList.stream().map(item -> {
            return createTestRecordSampleDataExpand(
                    testDataId,
                    item.getIsBasePeak() == 1 ? Boolean.TRUE : Boolean.FALSE,
                    item.getArea(),
                    item.getAbundanceRatio(),
                    item.getAbundanceRatioError(),
                    item.getWithinError(),
                    item.getRetTime(),
                    item.getMass(),
                    null, null
            );
        }).collect(Collectors.toList());

        return testRecordSampleDataExpandList;
    }

    /**
     * 根据业务类型保存检验数据扩展信息
     *
     * @param testDataId   检验数据id
     * @param drug         对应的标准品毒品清单
     * @param businessType 业务类型
     * @return
     */
    @Override
    public List<TestRecordSampleDataExpand> saveExpDataByBusinessType(String testDataId, Drug drug, String businessType) {
        List<TestRecordSampleDataExpand> testRecordSampleDataExpandList = new ArrayList<>();
        if (BusinessType.NPS_CASE.getBusinessType().equals(businessType)) {
            List<String> characteristicIonsList = StrUtil.split(drug.getCharacteristicIons(), "、");

            testRecordSampleDataExpandList = characteristicIonsList.stream().map(characteristicIons -> {
                TestRecordSampleDataExpand testRecordSampleDataExpand = new TestRecordSampleDataExpand();
                testRecordSampleDataExpand.setTestDataId(testDataId);
                if (characteristicIons.contains("*")) {
                    testRecordSampleDataExpand.setBasePeak(Boolean.TRUE);
                } else {
                    testRecordSampleDataExpand.setBasePeak(Boolean.FALSE);
                }
                // 如果有 * 号就替换掉
                testRecordSampleDataExpand.setMassToChargeRatio(new BigDecimal(characteristicIons.replace("*", "")));
                return testRecordSampleDataExpand;
            }).collect(Collectors.toList());
        } else {
            for (int i = 0; i < 2; i++) {
                TestRecordSampleDataExpand testRecordSampleDataExpand = new TestRecordSampleDataExpand();
                testRecordSampleDataExpand.setTestDataId(testDataId);
                if (i == 0) {
                    testRecordSampleDataExpand.setBasePeak(Boolean.TRUE);
                    testRecordSampleDataExpand.setQualitativeIonPair(drug.getMainProductIon());
                } else {
                    testRecordSampleDataExpand.setBasePeak(Boolean.FALSE);
                    testRecordSampleDataExpand.setQualitativeIonPair(drug.getMinorProductIon());
                }
                testRecordSampleDataExpandList.add(testRecordSampleDataExpand);
            }
        }

        return testRecordSampleDataExpandList;
    }

    /**
     * 根据DTO去批量更新
     *
     * @param dtoList
     * @param testId 这里实验id之所以需要是因为如果当前更新的也有标准品的，则应该先计算标准品的，避免计算样本检测的空指针异常
     * @return
     */
    @Override
    public Boolean updateBatchByDTO(List<TestSampleDataExpandDTO> dtoList, String testId) {
        List<TestRecordSampleDataExpand> expandList = TestSampleDataExpandConverter.dtoToEntityList(dtoList);
        if (super.updateBatchById(expandList)) {
//            CompletableFuture.runAsync(() -> {
                List<TestRecordSampleDataExpand> newExpandDatList = super.list(Wrappers.<TestRecordSampleDataExpand>lambdaQuery()
                        .in(TestRecordSampleDataExpand::getId, expandList.stream().map(TestRecordSampleDataExpand::getId).collect(Collectors.toList()))
                        .isNotNull(TestRecordSampleDataExpand::getPeakArea)
                );
                Map<String, List<TestRecordSampleDataExpand>> expandDataGroupByDataId = getexpandDataGroup(testId, newExpandDatList);

//                List<TestRecordSampleDataExpand> calculateAfterResult = new ArrayList<>();
                expandDataGroupByDataId.forEach((key, value) -> {
                    log.info("Key: " + key + ", Value Size: " + value.size());
                    // 查询对应的基峰数据是否存在
                    TestRecordSampleDataExpand basePeakData = value.stream().filter(TestRecordSampleDataExpand::getBasePeak).findFirst().orElse(null);

                    if (basePeakData != null) {
                        // 获取标准物质的扩展信息，1 先查询对应的实验数据 2 根据实验数据的实验id以及化合物以及类型获取标准物质的实验数据信息 3 根据标准物质实验数据id取对应的扩展数据
                        TestRecordSampleData testRecordSampleData = testRecordSampleDataService.getById(key);
                        boolean isSTDSample = testRecordSampleData.getSampleType().equals(TestRecordSampleDataConstant.SAMPLE_TYPE_STD);
                        TestRecord testRecord = testRecordService.getById(testRecordSampleData.getTestId());
                        List<TestRecordSampleDataExpand> stdDataExpandList = null;
                        if (!isSTDSample) {
                            TestRecordSampleData stdTestSampleData = testRecordSampleDataService.getOne(Wrappers.<TestRecordSampleData>lambdaQuery().eq(TestRecordSampleData::getTestId, testRecordSampleData.getTestId()).eq(TestRecordSampleData::getCompoundName, testRecordSampleData.getCompoundName()).eq(TestRecordSampleData::getSampleType, TestRecordSampleDataConstant.SAMPLE_TYPE_STD));
                            stdDataExpandList = super.list(Wrappers.<TestRecordSampleDataExpand>lambdaQuery().eq(TestRecordSampleDataExpand::getTestDataId, stdTestSampleData.getId()));
                        }
                        List<TestRecordSampleDataExpand> finalStdDataExpandList = stdDataExpandList;
                        testRecordSampleData.setIsDetected(1); // 默认检出
                        value.forEach(sampleDataExpand -> {
                            calculateIonAbundanceRatio(basePeakData, testRecord, finalStdDataExpandList, sampleDataExpand);
                             if (
                                     !isSTDSample &&
                                             testRecordSampleData.getIsDetected().equals(1) &&
                                             (
                                                     testRecordSampleData.getRtTimeWithinError().equals(TestRecordSampleDataConstant.NO)
                                                             || sampleDataExpand.getIonAbundanceRatioWithinError().equals(TestRecordSampleDataConstant.NO)
                                             )
                             ) {
                                testRecordSampleData.setIsDetected(0);
                            }
//                            calculateAfterResult.add(sampleDataExpand);
                        });
                        testRecordSampleData.setWhetherCheckOut(
                                (testRecordSampleData.getIsDetected().equals(1) ? TestRecordSampleDataConstant.CHECK_OUT : TestRecordSampleDataConstant.NOT_CHECK_OUT)
                                        + testRecordSampleData.getCompoundCnName()
                        );
                        testRecordSampleDataService.updateById(testRecordSampleData);
                        super.updateBatchById(value);
                    }
                });
//                if (CollUtil.isNotEmpty(calculateAfterResult)) {
//                    super.updateBatchById(calculateAfterResult);
//                }
//            }).exceptionally(e -> {
//                log.error("离子丰度比相关计算出错！");
//                e.printStackTrace();
//                return null;
//            });
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 根据测试ID和新的扩展数据列表，获取按数据ID分组的扩展数据， 如果testId不为空， 则会根据标准物质进行排序，先计算标准物质的
     *
     * @param testId 测试ID
     * @param newExpandDatList 新的扩展数据列表
     * @return 按数据ID分组的扩展数据
     */
    private Map<String, List<TestRecordSampleDataExpand>> getexpandDataGroup(String testId, List<TestRecordSampleDataExpand> newExpandDatList) {
        List<String> stdTestDataIds = null;
        if (StrUtil.isNotBlank(testId)) {
            List<TestRecordSampleData> stdSampleDataList = testRecordSampleDataService.list(Wrappers.<TestRecordSampleData>lambdaQuery().eq(TestRecordSampleData::getTestId, testId).eq(TestRecordSampleData::getSampleType, TestRecordSampleDataConstant.SAMPLE_TYPE_STD));
            stdTestDataIds = stdSampleDataList.stream().map(TestRecordSampleData::getId).collect(Collectors.toList());
        }
        Map<String, List<TestRecordSampleDataExpand>> expandDataGroupByDataId = newExpandDatList.stream().collect(Collectors.groupingBy(TestRecordSampleDataExpand::getTestDataId, LinkedHashMap::new, Collectors.toList()));
        if (stdTestDataIds != null && !stdTestDataIds.isEmpty()) {
            Map<String, List<TestRecordSampleDataExpand>> sortedMap = new LinkedHashMap<>();

            // 先按 stdTestDataIds 的顺序放入
            for (String stdTestDataId : stdTestDataIds) {
                if (expandDataGroupByDataId.containsKey(stdTestDataId)) {
                    sortedMap.put(stdTestDataId, expandDataGroupByDataId.get(stdTestDataId));
                }
            }

            // 再放入剩余的 key（不在 stdTestDataIds 里的）
            expandDataGroupByDataId.entrySet().stream()
                    .filter(entry -> !sortedMap.containsKey(entry.getKey()))
                    .forEach(entry -> sortedMap.put(entry.getKey(), entry.getValue()));

            // 替换原 map
            expandDataGroupByDataId = sortedMap;
        }
        return expandDataGroupByDataId;
    }

    /**
     * 计算离子丰度比
     *
     * @param basePeakData          基准峰数据
     * @param testRecord            测试记录
     * @param finalStdDataExpandList 最终标准数据扩展列表
     * @param sampleDataExpand      样本数据扩展
     */
    private void calculateIonAbundanceRatio(TestRecordSampleDataExpand basePeakData, TestRecord testRecord, List<TestRecordSampleDataExpand> finalStdDataExpandList, TestRecordSampleDataExpand sampleDataExpand) {
        if (sampleDataExpand.getPeakArea() != null && basePeakData.getPeakArea() != null) {
            sampleDataExpand.setIonAbundanceRatio(sampleDataExpand.getPeakArea().divide(basePeakData.getPeakArea(), 5, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)));
            if (CollUtil.isNotEmpty(finalStdDataExpandList)) {
                finalStdDataExpandList.forEach(stdDataExpand -> {
                    boolean matched = false; // 匹配对应的标准物质数据
                    boolean isNPSCase = testRecord.getBusinessType().equals(BusinessType.NPS_CASE.getBusinessType()); // 是否是常规毒品案件
                    if (isNPSCase) {
                        matched = stdDataExpand.getMassToChargeRatio().equals(sampleDataExpand.getMassToChargeRatio());
                    } else {
                        matched = stdDataExpand.getQualitativeIonPair().equals(sampleDataExpand.getQualitativeIonPair());
                    }
                    if (matched) {
                        BigDecimal ionAbundanceRatioError = sampleDataExpand.getIonAbundanceRatio()
                                .subtract(stdDataExpand.getIonAbundanceRatio())
                                .divide(stdDataExpand.getIonAbundanceRatio(), 5, BigDecimal.ROUND_HALF_UP)
                                .multiply(BigDecimal.valueOf(100));
                        sampleDataExpand.setIonAbundanceRatioError(ionAbundanceRatioError);
                        if (isNPSCase) {
                            // 取绝对值的原因是简化逻辑，不然需要判断正负值的范围
                            sampleDataExpand.setIonAbundanceRatioWithinError(
                                    processInspectDataService.getWithinErrorText(
                                            ionAbundanceRatioError.abs(),
                                            processInspectDataService.getErrorRange(stdDataExpand.getIonAbundanceRatio())
                                    )
                            );
                        } else {
                            sampleDataExpand.setIonAbundanceRatioWithinError(
                                    processInspectDataService.calculateHairCaseIonAbundanceRatioWithinError(
                                            ionAbundanceRatioError.doubleValue(),
                                            stdDataExpand.getIonAbundanceRatio().doubleValue()
                                    )
                            );
                        }
                    } else {
                        log.warn("没有找到匹配的标准物质检验数据！");
                    }
                });
            }
        }
    }

    /**
     * 根据提供的参数创建一个TestRecordSampleDataExpand对象。
     *
     * @param testDataId                   测试数据ID
     * @param isBasePeak                   是否为基本峰
     * @param peakArea                     峰面积
     * @param ionAbundanceRatio            离子丰度比
     * @param ionAbundanceRatioError       离子丰度比误差
     * @param ionAbundanceRatioWithinError 离子丰度比是否在误差范围内
     * @param retTime                      碎片保留时间，目前该字段仅对nps实验有用
     * @param mass                         质荷比(m/z)，nps案件
     * @param qualitativeIonPair           定性离子对，生物案件使用
     * @param someOtherValue               其他值
     * @return 创建的TestRecordSampleDataExpand对象
     */
    private TestRecordSampleDataExpand createTestRecordSampleDataExpand(
            String testDataId,
            Boolean isBasePeak,
            Double peakArea,
            Double ionAbundanceRatio,
            Double ionAbundanceRatioError,
            String ionAbundanceRatioWithinError,
            Double retTime,
            String mass,
            String qualitativeIonPair,
            Double someOtherValue
    ) {
        TestRecordSampleDataExpand testRecordSampleDataExpand = new TestRecordSampleDataExpand();
        testRecordSampleDataExpand.setTestDataId(testDataId);
        testRecordSampleDataExpand.setId(IdWorker.getIdStr());
        testRecordSampleDataExpand.setBasePeak(isBasePeak);
        testRecordSampleDataExpand.setPeakArea(BigDecimal.valueOf(peakArea));  // 注意: BigDecimal.valueOf(double)

        if (ionAbundanceRatio != null) {
            testRecordSampleDataExpand.setIonAbundanceRatio(BigDecimal.valueOf(ionAbundanceRatio));
        }

        if (ionAbundanceRatioError != null) {
            testRecordSampleDataExpand.setIonAbundanceRatioError(BigDecimal.valueOf(ionAbundanceRatioError));
        }

        if (ionAbundanceRatioWithinError != null) {
            testRecordSampleDataExpand.setIonAbundanceRatioWithinError(ionAbundanceRatioWithinError);
        }

        if (retTime != null) {
            testRecordSampleDataExpand.setFragmentRetTime(BigDecimal.valueOf(retTime));
        }

        if (StrUtil.isNotBlank(mass)) {
            testRecordSampleDataExpand.setMassToChargeRatio(new BigDecimal(mass));
        }

        // 如果有其他需要设置的值，可以继续扩展
        if (someOtherValue != null) {
            // 处理其他值的设置逻辑
        }

        return testRecordSampleDataExpand;
    }

}
