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

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import digital.laboratory.platform.common.core.util.R;
import digital.laboratory.platform.inspection.dto.TestRecordSampleSolutionDto;
import digital.laboratory.platform.inspetion.api.entity.SampleInfo;
import digital.laboratory.platform.inspection.entity.SampleInjector;
import digital.laboratory.platform.inspection.entity.TestRecordSampleSolution;
import digital.laboratory.platform.inspection.enums.TestRecordArgumentType;
import digital.laboratory.platform.inspection.mapper.TestRecordMapper;
import digital.laboratory.platform.inspection.mapper.TestRecordSampleSolutionMapper;
import digital.laboratory.platform.inspection.service.SampleInfoService;
import digital.laboratory.platform.inspection.service.SampleInjectorService;
import digital.laboratory.platform.inspection.service.TestRecordSampleSolutionService;
import digital.laboratory.platform.inspection.service.TestRecordService;
import digital.laboratory.platform.inspetion.api.vo.TestRecordVo;
import digital.laboratory.platform.sys.feign.RemoteBalanceRMaterialService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@SuppressWarnings("all")
public class TestRecordSampleSolutionServiceImpl extends ServiceImpl<TestRecordSampleSolutionMapper, TestRecordSampleSolution> implements TestRecordSampleSolutionService {

    @Resource
    private RemoteBalanceRMaterialService remoteBalanceRMaterialService;

    @Resource
    private TestRecordService testRecordService;

    @Resource
    private SampleInfoService sampleInfoService;

    @Resource
    private TestRecordMapper testRecordMapper;

    @Resource
    private SampleInjectorService sampleInjectorService;

    /**
     * 新增样本溶液
     *
     * @param testRecordSampleSolutionDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TestRecordSampleSolution addTestRecordSampleSolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto) {
        TestRecordSampleSolution testRecordSampleSolution = new TestRecordSampleSolution();
        BeanUtils.copyProperties(testRecordSampleSolutionDto, testRecordSampleSolution);
        SampleInfo sampleInfo = sampleInfoService.getById(testRecordSampleSolutionDto.getMaterialId());
        testRecordSampleSolution.setSampleShape(sampleInfo.getForm());
        testRecordSampleSolution.setId(IdWorker.get32UUID().toUpperCase());
        testRecordSampleSolution.setSampleNo(this.createSampleNo(testRecordSampleSolutionDto.getMaterialId(), testRecordSampleSolutionDto.getTestId()));//获取编号
//        SampleInfo sampleInfo = sampleInfoService.getOne(Wrappers.<SampleInfo>lambdaQuery().eq(SampleInfo::getAcceptNo, testRecordSampleSolutionDto.getSampleNo()));
//        if (sampleInfo == null) {
//            throw new RuntimeException(String.format("没有找到编号为%s的样本!", testRecordSampleSolutionDto.getSampleNo()));
//        }
        //计算浓度
        testRecordSampleSolution = this.calculatedConcentration(testRecordSampleSolution);
        Integer opCode = 1;//代表是向实验添加溶液
        boolean ret = testRecordService.updateTestRecordArgument(testRecordSampleSolution.getTestId(), testRecordSampleSolution.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_SAMPLE_SOLUTION.getType(), opCode);
        return this.save(testRecordSampleSolution) && ret ? testRecordSampleSolution : null;
    }

    /**
     * 创建编号
     *
     * @param testRecordSampleSolutionDto
     * @return
     */
    public String createSampleNo(String materialId, String testId) {
        SampleInfo sampleInfo = sampleInfoService.getById(materialId);
        String acceptNo = sampleInfo.getAcceptNo();

        //根据这个样本在实验中创建为溶液的次数来生成后缀，以便能自动匹配称量数据
        List<TestRecordSampleSolution> list = this.list(Wrappers.<TestRecordSampleSolution>lambdaQuery().eq(TestRecordSampleSolution::getMaterialId, materialId));

        if (list == null || list.size() == 0) {
            return acceptNo;
        } else if (list != null && list.size() == 1) {
            //判断是否已上样
            this.isLoadSample(acceptNo, testId);
            //选中同一样本创建第二个溶液时，要将第一个溶液的编号后缀修改为-1
            TestRecordSampleSolution testRecordSampleSolution = list.get(0);
            testRecordSampleSolution.setSampleNo(acceptNo + "-1");
            this.updateById(testRecordSampleSolution);
            return acceptNo + "-2";
        } else {
            return acceptNo + "-" + (list.size() + 1);
        }

    }

    /**
     * 删除样本溶液
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delTestRecordSampleSolution(String id) {
        TestRecordSampleSolution oldTestRecordSampleSolution = this.getOne(Wrappers.<TestRecordSampleSolution>lambdaQuery().eq(TestRecordSampleSolution::getId, id));
        Integer opCode = -1;//代表向实验删除这个溶液
        if (oldTestRecordSampleSolution == null) {
            throw new RuntimeException(String.format("没有找到ID为%s的样本溶液!", id));
        }
        this.isLoadSample(oldTestRecordSampleSolution.getSampleNo(), oldTestRecordSampleSolution.getTestId());
        List<TestRecordSampleSolution> list = this.list(Wrappers.<TestRecordSampleSolution>lambdaQuery().eq(TestRecordSampleSolution::getMaterialId, oldTestRecordSampleSolution.getMaterialId()));
        if (list.size() == 2) {
            list.remove(oldTestRecordSampleSolution);
            TestRecordSampleSolution testRecordSampleSolution = list.get(0);
            String sampleNo = testRecordSampleSolution.getSampleNo();
            this.isLoadSample(sampleNo, testRecordSampleSolution.getTestId());
            int lastInde = sampleNo.lastIndexOf("-");
            String newSampleNo = sampleNo.substring(0, lastInde);
            testRecordSampleSolution.setSampleNo(newSampleNo);
            this.updateById(testRecordSampleSolution);
        }
        boolean ret = testRecordService.updateTestRecordArgument(oldTestRecordSampleSolution.getTestId(), oldTestRecordSampleSolution.getId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_SAMPLE_SOLUTION.getType(), opCode);
        return this.removeById(id) && ret;
    }

    /**
     * 修改样本溶液
     *
     * @param testRecordSampleSolutionDto
     * @return
     */
    @Override
    public TestRecordSampleSolution updateTestRecordSampleSolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto) {
        TestRecordSampleSolution oldTestRecordSampleSolution = this.getOne(Wrappers.<TestRecordSampleSolution>lambdaQuery().eq(TestRecordSampleSolution::getId, testRecordSampleSolutionDto.getId()));
        if (oldTestRecordSampleSolution == null) {
            throw new RuntimeException(String.format("没有找到ID为%s的样本溶液!", testRecordSampleSolutionDto.getId()));
        }
        BeanUtils.copyProperties(testRecordSampleSolutionDto, oldTestRecordSampleSolution);
        //计算浓度
        oldTestRecordSampleSolution = this.calculatedConcentration(oldTestRecordSampleSolution);
        return this.updateById(oldTestRecordSampleSolution) ? oldTestRecordSampleSolution : null;
    }

    /**
     * 计算浓度
     *
     * @param testRecordSampleSolution
     * @return
     */
    public TestRecordSampleSolution calculatedConcentration(TestRecordSampleSolution testRecordSampleSolution) {
        //计算原始浓度
        if (StrUtil.isNotBlank(testRecordSampleSolution.getWeighingValue())) {
            BigDecimal weighingValue = new BigDecimal(testRecordSampleSolution.getWeighingValue());
            BigDecimal constantVolume = new BigDecimal(testRecordSampleSolution.getConstantVolume());
            BigDecimal originalConcentration = weighingValue.divide(constantVolume, 2, RoundingMode.HALF_UP);
            testRecordSampleSolution.setOriginalConcentration(originalConcentration.toString());
        }

        //计算结果浓度
        if (StrUtil.isNotBlank(testRecordSampleSolution.getOriginalConcentration()) && StrUtil.isNotBlank(testRecordSampleSolution.getDilutionFactor()) && !testRecordSampleSolution.getDilutionFactor().equals("/")) {
            BigDecimal originalConcentration = new BigDecimal(testRecordSampleSolution.getOriginalConcentration());
            BigDecimal dilutionFactor = new BigDecimal(testRecordSampleSolution.getDilutionFactor());
            BigDecimal resultConcentration = originalConcentration.divide(dilutionFactor, 2, RoundingMode.HALF_UP);
            testRecordSampleSolution.setResultConcentration(resultConcentration.toString());
        }
        return testRecordSampleSolution;
    }

    /**
     * 列表查询
     *
     * @param testId
     * @param keywords 样本编号模糊查询
     * @return
     */
    @Override
    public List<TestRecordSampleSolution> getSolutionList(String testId, String keywords) {
        return this.list(Wrappers.<TestRecordSampleSolution>lambdaQuery()
                .eq(TestRecordSampleSolution::getTestId, testId)
                .like(StrUtil.isNotBlank(keywords), TestRecordSampleSolution::getSampleNo, keywords)
                .orderByAsc(TestRecordSampleSolution::getSampleNo));
    }

    /**
     * 分页查询
     *
     * @param testId
     * @param page
     * @param keywords 样本编号模糊查询
     * @return
     */
    @Override
    public IPage<TestRecordSampleSolution> getSolutionPage(Page<TestRecordSampleSolution> page, String testId, String keywords) {
        return this.page(page, Wrappers.<TestRecordSampleSolution>lambdaQuery()
                .eq(TestRecordSampleSolution::getTestId, testId)
                .like(StrUtil.isNotBlank(keywords), TestRecordSampleSolution::getSampleNo, keywords)
                .orderByAsc(TestRecordSampleSolution::getSampleNo));
    }

    /**
     * ]
     * 匹配称量数据
     *
     * @param id
     * @return
     */
    @Override
    public List<TestRecordSampleSolution> matchingWeighing(String id) {
        List<TestRecordSampleSolution> testRecordSampleSolutionList = this.list(Wrappers.<TestRecordSampleSolution>lambdaQuery().eq(TestRecordSampleSolution::getTestId, id));
        if (testRecordSampleSolutionList.size() == 0) {
            throw new RuntimeException(String.format("没有找到ID为%s的实验!", id));
        }
        Map<String, List<TestRecordSampleSolution>> map = testRecordSampleSolutionList.stream().collect(Collectors.groupingBy(item -> item.getMaterialId()));

        List<TestRecordSampleSolution> sampleSolutions = new ArrayList<>();
        Set<String> keySet = map.keySet();

        List<String> idList = new ArrayList<>();
        for (String key : keySet) {
            List<TestRecordSampleSolution> solutionList = map.get(key);
            if (solutionList.size() == 1) {
                TestRecordSampleSolution solution = solutionList.get(0);
                idList.add(solution.getId());
            }
            sampleSolutions.addAll(solutionList);
        }

        //如果匹配到了称量质量，那么就自动去计算浓度
        for (TestRecordSampleSolution testRecordSampleSolution : sampleSolutions) {
            String weighingNum = "";
            if (idList.contains(testRecordSampleSolution.getId())) {
                weighingNum = testRecordSampleSolution.getSampleNo() + "-1";
            } else {
                weighingNum = testRecordSampleSolution.getSampleNo();
            }
            R<BigDecimal> data = remoteBalanceRMaterialService.getWeightForNumber(weighingNum);
            BigDecimal weighing = data.getData();
            if (weighing.compareTo(BigDecimal.ZERO) != 0) {
                //计算原始浓度
                testRecordSampleSolution.setWeighingValue(weighing.toString());
                BigDecimal constantVolume = new BigDecimal(testRecordSampleSolution.getConstantVolume());
                BigDecimal originalConcentration = weighing.divide(constantVolume, 2, RoundingMode.HALF_UP);
                testRecordSampleSolution.setOriginalConcentration(originalConcentration.toString());
                //计算结果浓度
                if (StrUtil.isNotBlank(testRecordSampleSolution.getDilutionFactor())) {
                    BigDecimal dilutionFactor = new BigDecimal(testRecordSampleSolution.getDilutionFactor());
                    BigDecimal resultConcentration = originalConcentration.divide(dilutionFactor, 2, RoundingMode.HALF_UP);
                    testRecordSampleSolution.setResultConcentration(resultConcentration.toString());
                } else {
                    testRecordSampleSolution.setResultConcentration(originalConcentration.toString());
                }
            }
        }
        return this.updateBatchById(testRecordSampleSolutionList) ? testRecordSampleSolutionList : null;
    }

    /**
     * 为任务创建所有检材对应的样本溶液
     *
     * @param testId
     * @return
     */
    @Override
    public boolean createTaskSamSol(String testId) {
        TestRecordVo vo = testRecordMapper.getTestRecordMapById(testId);
        if (StringUtils.isNotBlank(vo.getBusinessType()) && !vo.getBusinessType().startsWith("2")) {
            return true;
        }
        List<String> sampleSolutionList = new ArrayList<>();
        List<String> sampleTestList = vo.getSampleTestList();
        this.remove(Wrappers.<TestRecordSampleSolution>lambdaQuery().eq(TestRecordSampleSolution::getTestId, testId));
        if (sampleTestList != null && sampleTestList.size() > 0) {
            List<TestRecordSampleSolution> solutions = new ArrayList<>();
            List<SampleInfo> sampleInfoList = sampleInfoService.list(Wrappers.<SampleInfo>lambdaQuery().in(SampleInfo::getId, sampleTestList));
            for (SampleInfo sampleInfo : sampleInfoList) {
                TestRecordSampleSolution testRecordSampleSolution = new TestRecordSampleSolution();
                testRecordSampleSolution.setId(IdWorker.get32UUID().toUpperCase());
                testRecordSampleSolution.setSampleNo(sampleInfo.getAcceptNo());
                testRecordSampleSolution.setMaterialId(sampleInfo.getId());
                testRecordSampleSolution.setTestId(vo.getId());
                testRecordSampleSolution.setSampleShape("/");
                testRecordSampleSolution.setDilutionName("/");
                testRecordSampleSolution.setConstantVolume("0.0");
                testRecordSampleSolution.setDilutionFactor("0");
                testRecordSampleSolution.setOriginalConcentration("/");
                testRecordSampleSolution.setResultConcentration("/");
                testRecordSampleSolution.setWeighingValue("/");
                solutions.add(testRecordSampleSolution);
                sampleSolutionList.add(testRecordSampleSolution.getId());
            }
            vo.setSampleSolution(sampleSolutionList);
            testRecordService.updateById(vo);
            return this.saveBatch(solutions);
        } else return true;
    }

    /*
     * 复制样品溶液
     *
     * @param testRecordSampleSolutionDto
     * @return
     */
    @Override
    public List<TestRecordSampleSolution> copySolution(TestRecordSampleSolutionDto testRecordSampleSolutionDto) {
        TestRecordSampleSolution sampleSolution = this.getById(testRecordSampleSolutionDto.getId());
        List<String> materialIdList = testRecordSampleSolutionDto.getMaterialIdList();
        ArrayList<TestRecordSampleSolution> testRecordSampleSolutions = new ArrayList<>();
        TestRecordVo vo = testRecordMapper.getTestRecordMapById(sampleSolution.getTestId());
        List<String> solutionIdList = new ArrayList<>();
        for (String id : materialIdList) {
            SampleInfo sampleInfo = sampleInfoService.getById(id);
            String acceptNo = sampleInfo.getAcceptNo();
            String sampleNo = this.createSampleNo(id, testRecordSampleSolutionDto.getTestId());
            TestRecordSampleSolution testRecordSampleSolution = new TestRecordSampleSolution();
            BeanUtils.copyProperties(sampleSolution, testRecordSampleSolution);
            testRecordSampleSolution.setCreateBy(null);
            testRecordSampleSolution.setUpdateBy(null);
            testRecordSampleSolution.setCreateTime(null);
            testRecordSampleSolution.setUpdateTime(null);
            testRecordSampleSolution.setId(IdWorker.get32UUID().toUpperCase());
            testRecordSampleSolution.setSampleNo(sampleNo);
            testRecordSampleSolution.setMaterialId(id);
            testRecordSampleSolution.setSampleShape(sampleInfo.getForm());
            testRecordSampleSolutions.add(testRecordSampleSolution);
            solutionIdList.add(testRecordSampleSolution.getId());
        }
        List<String> voSampleSolution = vo.getSampleSolution();
        voSampleSolution.addAll(solutionIdList);
        vo.setSampleSolution(voSampleSolution);
        if (this.saveBatch(testRecordSampleSolutions) && testRecordService.updateById(vo)) {
            return testRecordSampleSolutions;
        } else return null;
    }

    @Override
    public void isLoadSample(String acceptNo, String testId) {
        SampleInjector sampleInjector = sampleInjectorService.getOne(Wrappers.<SampleInjector>lambdaQuery().eq(SampleInjector::getTestId, testId));
        if (sampleInjector == null) {
            return;
        }
        String injectorInfo = sampleInjector.getInjectorInfo();
        if (injectorInfo == null) {
            return;
        }
        JSONArray jsonArray = JSON.parseArray(injectorInfo);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            if (jsonObject.getString("sampleNo").equals(acceptNo)) {
                throw new RuntimeException(String.format("编号为：%s的溶液已存在上样记录，请先修改上样记录后再进行操作!", acceptNo));
            }
        }
    }
}
