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

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
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.aop.annotation.DlpResultProc;
import digital.laboratory.platform.inspection.enums.TestRecordArgumentType;
import digital.laboratory.platform.inspection.convert.TestRecordReagentConverter;
import digital.laboratory.platform.inspection.dto.TestRecordArgumentDto;
import digital.laboratory.platform.inspection.entity.TestRecordReagent;
import digital.laboratory.platform.inspection.mapper.TestRecordMapper;
import digital.laboratory.platform.inspection.mapper.TestRecordReagentMapper;
import digital.laboratory.platform.inspection.mapper.TestTemplateMapper;
import digital.laboratory.platform.inspection.service.TestRecordReagentService;
import digital.laboratory.platform.inspection.service.TestRecordSampleDataService;
import digital.laboratory.platform.inspection.service.TestRecordService;
import digital.laboratory.platform.inspection.service.TestTemplateService;
import digital.laboratory.platform.inspection.vo.TestRecordReagentVO;
import digital.laboratory.platform.inspection.vo.TestTemplateVo;
import digital.laboratory.platform.inspetion.api.vo.TestRecordVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xy
 * @version 1.0
 * @title TestRecordReagentServiceImpl
 * @description
 * @create 2023/12/20 11:15
 */
@Service
@Slf4j
public class TestRecordReagentServiceImpl extends ServiceImpl<TestRecordReagentMapper, TestRecordReagent> implements TestRecordReagentService {

    @Resource
    private TestRecordService testRecordService;
    @Resource
    private TestRecordMapper testRecordMapper;

    @Resource
    private TestTemplateService testTemplateService;
    @Resource
    private TestTemplateMapper testTemplateMapper;

    @Resource
    private TestRecordSampleDataService testRecordSampleDataService;

    /**
     * 根据id获取vo类
     * @param id
     * @return
     */
    @Override
    @DlpResultProc
    public TestRecordReagentVO getVOById(String id) {
        return TestRecordReagentConverter.entityToVO(super.getById(id));
    }

    /**
     * 根据wrapper获取vo类
     * @param queryWrapper
     * @return
     */
    @Override
    @DlpResultProc
    public List<TestRecordReagentVO> voListByWrapper(Wrapper<TestRecordReagent> queryWrapper) {
        return TestRecordReagentConverter.entityToVOList(super.list(queryWrapper));
    }

    @Override
    public TestRecordReagent addTestRecordReagent(TestRecordReagent testRecordReagent) {
        if (StringUtils.isBlank(testRecordReagent.getId())) {
            testRecordReagent.setId(IdWorker.get32UUID());
            log.info("保存对象testRecordReagent的ID为空，由系统生成一个给它使用 {}", testRecordReagent.getId());
        }
        if (!testRecordReagent.getCategory().equals("试剂")) {
            testRecordReagent.setPurityGrade("/");
        }
        boolean ret = this.save(testRecordReagent);
        if (ret) {
            log.info("{} 保存成功", testRecordReagent);
            return testRecordReagent;
        } else {
            log.info("{} 保存失败", testRecordReagent);
            return null;
        }
    }

    @Override
    public TestRecordReagent updateTestRecordReagent(TestRecordReagent testRecordReagent) {
//        todo 添加了标准品成分，必填，其他系统过来的可以修改
//        if (testRecordReagent.getSource() == 0) {
//            throw new CheckedException("数据是其他系统推送录入的，不能修改");
//        }
        boolean ret = this.updateById(testRecordReagent);
        if (ret) {
            return testRecordReagent;
        } else {
            return null;
        }
    }

    /**
     * 删除试剂耗材
     *
     * @param id
     * @return
     */
    @Override
    public Boolean deleteTestRecordReagent(String id) {
        TestRecordReagent recordReagent = this.getById(id);
        List<TestRecordVo> recordMapList = testRecordMapper.getTestRecordMapList(new LambdaQueryWrapper());
        List<TestTemplateVo> testTemplateMapList = testTemplateMapper.getTestTemplateMapList(new LambdaQueryWrapper());
        recordMapList.forEach(item -> {
            if (item.getReagentConsumablesList() != null && item.getReagentConsumablesList().size() > 0 && item.getReagentConsumablesList().contains(recordReagent.getId())) {
                throw new RuntimeException(String.format("该试剂耗材/标准物质已绑定编号为%s的实验，无法删除!", item.getTestSerialNumber()));
            }
        });
        testTemplateMapList.forEach(item -> {
            if (item.getReagentConsumables() != null && item.getReagentConsumables().size() > 0 && item.getReagentConsumables().contains(recordReagent.getId())) {
                throw new RuntimeException(String.format("该试剂耗材/标准物质已绑定ID为%s的模板，无法删除!", item.getId()));
            }
        });
        return this.removeById(id);
    }

    /**
     * 实验分页查询
     *
     * @param page
     * @param testId
     * @param keywords 标准物质编号、名称查询参数
     * @param category 类别查询参数
     * @param opCode   1：查询所有的试剂耗材 -1：查询这个实验下的试剂耗材
     * @return
     */
    @Override
    @DlpResultProc
    public IPage<TestRecordReagentVO> getTestRecordReagentPageList(Page page, String testId, String keywords, String category, Integer opCode) {
        List<String> categoryList = getCategoryList(category);
        TestRecordVo testRecordVo = testRecordMapper.getTestRecordMapById(testId);
        return testRecordReagentPage(page, keywords, opCode, categoryList, testRecordVo.getReagentConsumablesList());
    }

    /**
     * 模板分页查询
     *
     * @param page
     * @param templateId
     * @param keywords 标准物质编号、名称查询参数
     * @param category 类别查询参数
     * @param opCode   1：查询所有的试剂耗材 -1：查询这个模板下的试剂耗材
     * @return
     */
    @Override
    @DlpResultProc
    public IPage<TestRecordReagentVO> getTestTemplateReagentPageList(Page page, String templateId, String keywords, String category, Integer opCode) {
        List<String> categoryList = getCategoryList(category);
        TestTemplateVo templateVo = testTemplateMapper.getTestTemplateMapById(templateId);
        return testRecordReagentPage(page, keywords, opCode, categoryList, templateVo.getReagentConsumables());
    }

    /**
     * 分页查询试剂耗材记录
     *
     * @param page 分页参数
     * @param keywords 关键词，用于模糊查询试剂耗材编号或名称
     * @param opCode 操作码，用于区分查询类型
     * @param categoryList 试剂耗材类别列表，用于筛选符合条件的记录
     * @param reagentConsumablesList 试剂耗材ID列表，用于筛选符合条件的记录
     * @return 分页结果
     */
    public IPage<TestRecordReagentVO> testRecordReagentPage(Page page, String keywords, Integer opCode, List<String> categoryList, List<String> reagentConsumablesList) {
        LambdaQueryWrapper<TestRecordReagent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.and(StringUtils.isNotBlank(keywords), qw -> qw
                        .like(TestRecordReagent::getNumber, keywords)
                        .or()
                        .like(TestRecordReagent::getReagentConsumableName, keywords))
                .in(TestRecordReagent::getCategory, categoryList);
        if (opCode == 1) {//查询所有的试剂耗材、标准物质(去重处理)
            queryWrapper.orderByDesc(TestRecordReagent::getCreateTime);
            if (reagentConsumablesList != null && reagentConsumablesList.size() > 0) {
                queryWrapper.notIn(TestRecordReagent::getId, reagentConsumablesList);
            }
        } else {//查询这个模板中绑定的试剂耗材
            if (reagentConsumablesList == null || reagentConsumablesList.size() == 0) {
                //下面两步是为了能使参数正常查询
                reagentConsumablesList = new ArrayList<>();
                reagentConsumablesList.add("");
            }
            queryWrapper.in(TestRecordReagent::getId, reagentConsumablesList)
                    .orderByDesc(TestRecordReagent::getUpdateTime);
        }
        return TestRecordReagentConverter.entityToVOPage(this.page(page, queryWrapper));
    }

    /**
     * 实验列表查询
     *
     * @param testId
     * @param category 类别查询参数
     * @return
     */
    @Override
    public List<TestRecordReagent> getTestRecordReagentList(String testId, String category) {
        List<String> categoryList = getCategoryList(category);
        TestRecordVo testRecordVo = testRecordMapper.getTestRecordMapById(testId);
        List<String> reagentConsumablesList = testRecordVo.getReagentConsumablesList();
        if (reagentConsumablesList == null || reagentConsumablesList.size() == 0) {
            //下面两步是为了能使参数正常查询
            reagentConsumablesList = new ArrayList<>();
            reagentConsumablesList.add("");
        }
        LambdaQueryWrapper<TestRecordReagent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .in(TestRecordReagent::getCategory, categoryList).in(TestRecordReagent::getId, reagentConsumablesList)
                .orderByDesc(TestRecordReagent::getUpdateTime);
        //给了实验ID，查询这个实验下的试剂耗材、标准物质
        return this.list(queryWrapper);
    }

    @Override
    public Boolean checkExist(String id) {
        List<TestRecordReagent> retList = this.list(Wrappers.<TestRecordReagent>lambdaQuery()
                .eq(TestRecordReagent::getId, id));
        if (retList.size() > 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 向实验添加或移除试剂耗材
     *
     * @param testRecordArgumentDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean useTestRecordReagent(TestRecordArgumentDto testRecordArgumentDto) {
        TestRecordReagent testRecordReagent = this.getById(testRecordArgumentDto.getArgumentId());
        if (testRecordReagent.getCategory().equals("标准物质")) {
            Integer opCode = testRecordArgumentDto.getOpCode();
            if (opCode == 1) {
                testRecordSampleDataService.autoCreateData(testRecordArgumentDto.getTestRecordId(), testRecordArgumentDto.getArgumentId());
            }else if (opCode == -1) {
                testRecordSampleDataService.autoDelData(testRecordArgumentDto.getTestRecordId(), testRecordArgumentDto.getArgumentId());
            }
        }
        testRecordReagent.setUpdateTime(LocalDateTime.now());
        return this.updateById(testRecordReagent) && testRecordService.updateTestRecordArgument(testRecordArgumentDto.getTestRecordId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_REAGENT.getType(), testRecordArgumentDto.getOpCode());
    }

    /**
     * 向模板添加或移除试剂耗材
     *
     * @param testRecordArgumentDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean useTestTemplateReagent(TestRecordArgumentDto testRecordArgumentDto) {
        TestRecordReagent testRecordReagent = this.getById(testRecordArgumentDto.getArgumentId());
        testRecordReagent.setUpdateTime(LocalDateTime.now());
        boolean ret = testTemplateService.updateTestTemplate(testRecordArgumentDto.getTemplateId(), testRecordArgumentDto.getArgumentId(), TestRecordArgumentType.TEST_RECORD_ARGUMENT_REAGENT.getType(), testRecordArgumentDto.getOpCode());
        return this.updateById(testRecordReagent) && ret;
    }


    /**
     * 根据传入的类别名称返回相应的类别列表
     *
     * @param category 类别名称，只能是"试剂耗材"或其他字符串
     * @return 返回一个包含两个字符串的列表，具体内容取决于传入的类别名称
     *         如果类别名称为"试剂耗材"，则列表包含"试剂"和"耗材"
     *         否则，列表包含"标准物质"和"标准储备溶液"
     */
    private List<String> getCategoryList(String category) {
        List<String> categoryList = new ArrayList<>();
        if (category.equals("试剂耗材")) {
            categoryList.add("试剂");
            categoryList.add("耗材");
        } else {
            categoryList.add("标准物质");
            categoryList.add("标准储备溶液");
        }
        return categoryList;
    }
}
