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

import digital.laboratory.platform.inspection.constant.TestRecordSampleDataConstant;
import digital.laboratory.platform.inspection.dto.HairSewageDataDto;
import digital.laboratory.platform.inspection.service.ProcessInspectDataService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * @author ChenJiangBao
 * @version 1.0
 * @description: 处理检验数据接口 实现类
 * @date 2025/3/24 9:57
 */
@Service
public class ProcessInspectDataServiceImpl implements ProcessInspectDataService {

    //设置是否在误差范围内
    @Override
    public String getWithinErrorText(BigDecimal actualValue, BigDecimal expectedValue) {
        if (actualValue.compareTo(expectedValue) < 0) { // actualValue < expectedValue
            return TestRecordSampleDataConstant.IS;
        } else {
            return TestRecordSampleDataConstant.NO;
        }
    }


    //判断保留时间范围是否符合
    @Override
    public String getRtWithinErrorText(double targetRtErr, double errorRange) {
        if (targetRtErr < errorRange) {
            return TestRecordSampleDataConstant.IS;
        } else {
            return TestRecordSampleDataConstant.NO;
        }

    }

    /**
     * 计算离子丰度比 相对偏差 (目标物离子丰度比 - 标准物离子丰度比) / 标准物质离子丰度比 * 100
     *
     * @param ionAbundanceRatioWithinError 检测样本的丰度比偏差
     * @param stdIonAbundanceRatio 标准物质的离子丰度比
     */
    @Override
    public String calculateHairCaseIonAbundanceRatioWithinError(double ionAbundanceRatioWithinError, double stdIonAbundanceRatio) {

        // 判断是否在离子丰度比允许的最大偏差范围
        return setHairCaseWhetherCheckOut(
                Math.abs(ionAbundanceRatioWithinError),
                getHairCaseIonAbundanceRatioWithinErrorRange(stdIonAbundanceRatio));
    }

    /**
     * 根据给定的标准离子丰度比获取生物样本案件离子丰度比相对误差范围内的最大允许相对误差
     *
     * @param stdIonAbundanceRatio 标准离子丰度比
     * @return 发案离子丰度比允许的最大误差值
     */
    @Override
    public Double getHairCaseIonAbundanceRatioWithinErrorRange(double stdIonAbundanceRatio) {

        // 判断是否在离子丰度比允许的最大偏差范围
        if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_1) {

            return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_1;
        } else if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_2
                && stdIonAbundanceRatio <= TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_1) {

            return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_2;
        } else if (stdIonAbundanceRatio > TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_3
                && stdIonAbundanceRatio <= TestRecordSampleDataConstant.HAIR_CASE_ION_ABUNDANCE_RATIO_2) {

            return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_3;
        } else {
            return TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_MAX_ALLOW_ERROR_4;
        }
    }

    /**
     * 计算离子丰度比偏差
     *
     * @param sampleIonAbundanceRatio 目标物的离子丰度比
     * @param stdIonAbundanceRatio 标准物质的离子丰度比
     * @return
     */
    @Override
    public double getAbundanceRatioErrorValue(double sampleIonAbundanceRatio, double stdIonAbundanceRatio) {
        double diffValue = sampleIonAbundanceRatio - stdIonAbundanceRatio;
        double abundanceRatioErrorValue = Math.abs(diffValue) / stdIonAbundanceRatio * 100;
        return abundanceRatioErrorValue;
    }

    /**
     * 计算相对误差  (目标物保留时间 - 标准物保留时间) / 标准物质保留时间 * 100
     *
     * @param hairSewageDataDto
     * @param hairSewageDataDtoStd
     */
    @Override
    public void calculateHairCaseRtTimeError(HairSewageDataDto hairSewageDataDto, HairSewageDataDto hairSewageDataDtoStd) {
        if ( !TestRecordSampleDataConstant.isInvalidValue(hairSewageDataDto.getTargetRtTime()) ) {
            // 计算保留时间的相对误差
            BigDecimal rtTimeError = getHairCaseRtTimeError(hairSewageDataDto.getTargetRtTime(), hairSewageDataDtoStd.getStdRtTime());
            hairSewageDataDto.setRtTimeError(rtTimeError.doubleValue());
            // 判断保留时间相对误差是否符合误差范围
            hairSewageDataDto.setRtTimeWithinError(setHairCaseRtTimeWithinError(hairSewageDataDto.getRtTimeError()));
        } else {
            hairSewageDataDto.setRtTimeError(TestRecordSampleDataConstant.INVALID_VALUE);
            hairSewageDataDto.setRtTimeWithinError("/");
        }
    }

    /**
     * 计算保留时间的相对误差
     *
     * @param targetRtTime 目标物保留时间信息
     * @param stdRtTime    标准物保留时间信息
     * @return
     */
    @Override
    public BigDecimal getHairCaseRtTimeError(double targetRtTime, double stdRtTime) {
        return BigDecimal.valueOf((targetRtTime - stdRtTime) / stdRtTime * 100);
    }

    /**
     * 判断保留时间相对误差是否符合误差范围
     *
     * @param rtTimeError
     */
    @Override
    public String setHairCaseRtTimeWithinError(double rtTimeError) {
        if (rtTimeError > TestRecordSampleDataConstant.HAIR_CASE_NEGATIVE_RT_ERROR
                && rtTimeError < TestRecordSampleDataConstant.HAIR_CASE_POSITIVE_RT_ERROR) {
            return TestRecordSampleDataConstant.IS;
        } else {
            return TestRecordSampleDataConstant.NO;
        }
    }

    /**
     * 获取碎片的丰度比偏差范围
     *
     * @param abundanceRatio
     * @return
     */
    @Override
    public BigDecimal getErrorRange(BigDecimal abundanceRatio) {
        double retValue;
        if (abundanceRatio.compareTo(BigDecimal.valueOf(50)) > 0) { // abundanceRatio > 50
            retValue = 10;
        } else if (abundanceRatio.compareTo(BigDecimal.valueOf(20)) > 0) { // abundanceRatio > 20
            retValue = 15;
        } else if (abundanceRatio.compareTo(BigDecimal.valueOf(10)) > 0) { // abundanceRatio > 10
            retValue = 20;
        } else {
            retValue = 50;
        }
        return BigDecimal.valueOf(retValue);
    }


    /**
     * 根据计算出来的离子丰度比误差来判断是否检出
     *
     * @param ionAbundanceRatioWithinError
     * @param positive
     */
    private String setHairCaseWhetherCheckOut(double ionAbundanceRatioWithinError, double positive) {
        if (ionAbundanceRatioWithinError < positive) {
            return TestRecordSampleDataConstant.IS;
        } else {
            return TestRecordSampleDataConstant.NO;
        }
    }

}
