package com.casic.missiles.service.Impl.business;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import com.casic.missiles.constants.MeterDictCode;
import com.casic.missiles.core.application.service.AbstractDictService;
import com.casic.missiles.core.model.auth.AuthUser;
import com.casic.missiles.core.page.PageFactory;
import com.casic.missiles.core.shiro.ShiroKit;
import com.casic.missiles.dto.ReturnDTO;
import com.casic.missiles.dto.ReturnUtil;
import com.casic.missiles.dto.business.labExecutive.*;
import com.casic.missiles.enums.BusinessExceptionEnum;
import com.casic.missiles.enums.PrefixCodeEnum;
import com.casic.missiles.enums.business.HandOutPropertyEnum;
import com.casic.missiles.enums.business.MeasureStatusEnum;
import com.casic.missiles.enums.business.OrderStatusEnum;
import com.casic.missiles.enums.meter.MeterDictEnum;
import com.casic.missiles.enums.sample.CurrentSegmentEnum;
import com.casic.missiles.enums.sample.SampleStatusEnum;
import com.casic.missiles.enums.system.ApprovalStatusEnum;
import com.casic.missiles.exception.BusinessException;
import com.casic.missiles.mapper.business.*;
import com.casic.missiles.mapper.meter.MeterOrganizeMapper;
import com.casic.missiles.mapper.meter.MeterStaffMapper;
import com.casic.missiles.model.business.*;
import com.casic.missiles.model.meter.MeterStaff;
import com.casic.missiles.service.business.IBusinessLabExecutiveInfoService;
import com.casic.missiles.service.business.IBusinessLabExecutiveTemplateInfoService;
import com.casic.missiles.utils.ConvertUtils;
import com.casic.missiles.utils.DictCodeUtils;
import com.casic.missiles.utils.NumberGeneratorUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务管理-实验室检定信息记录表（用于流程中的实验室分配及后续检定过程查询） 服务实现类
 * </p>
 *
 * @author wangpeng
 * @since 2023-02-02
 */
@Slf4j
@Service
public class BusinessLabExecutiveInfoServiceImpl extends ServiceImpl<BusinessLabExecutiveInfoMapper, BusinessLabExecutiveInfo> implements IBusinessLabExecutiveInfoService {
    @Autowired
    private BusinessLabExecutiveInfoMapper labExecutiveInfoMapper;
    @Autowired
    private BusinessCertificateReportMapper certificateReportMapper;
    @Autowired
    private BusinessOrderSampleRelationMapper orderSampleRelationMapper;
    @Autowired
    private BusinessLabExecutiveOperateLogMapper labExecutiveOperateLogMapper;
    @Autowired
    private IBusinessLabExecutiveTemplateInfoService labExecutiveTemplateInfoService;
    @Autowired
    private BusinessLabExecutiveTemplateInfoMapper labExecutiveTemplateInfoMapper;
    @Autowired
    private MeterOrganizeMapper organizeMapper;
    @Autowired
    private AbstractDictService dictService;
    @Autowired
    private MeterStaffMapper staffMapper;
    @Autowired
    private BusinessOrderMapper orderMapper;

    @Override
    public Page<SampleHandOutListResponse> handOutListPage(Page<SampleHandOutListResponse> page, SampleHandOutListRequest handOutListRequest) throws Exception{
        //查询委托书和样品关联表中的各状态的样品
        Page<SampleHandOutListResponse> handOutList = orderSampleRelationMapper.selectSampleListByStatus(page, handOutListRequest);
        log.info("任务分发-当前查询样品状态为：{}", handOutListRequest.getSampleStatus());
        List<SampleHandOutListResponse> records = handOutList.getRecords();
        if(CollectionUtils.isEmpty(records)){
            return new Page<>();
        }
        records.parallelStream().forEach(handOut -> {
            Long orderId = handOut.getOrderId();
            Long sampleId = handOut.getSampleId();
            String sampleStatus = handOutListRequest.getSampleStatus();
            switch (sampleStatus) {
                //待分发状态，分发性质:有退回就是退回分发，当前检定环节:待分配，已出具证书：无，出具证书总数:无
                case SampleStatusEnum.TO_HANDOUT:
                    List<BusinessLabExecutiveOperateLog> sendBackOperateLogs = labExecutiveOperateLogMapper.selectList(getOperateLogWrapper(handOut));
                    if (CollectionUtils.isEmpty(sendBackOperateLogs)) {
                        handOut.setHandOutProperty(HandOutPropertyEnum.FIRST_HANDOUT);
                    } else {
                        handOut.setHandOutProperty(HandOutPropertyEnum.SEND_BACK_HANDOUT);
                    }
                    handOut.setCurrentSegment(CurrentSegmentEnum.TO_ALLOCATE);
                    break;
                //检测中状态，分发性质:无，当前检定环节:具体实验室，已出具证书：查询证书报告表，证书总数：具体实验室
                case SampleStatusEnum.IN_MEASURE:
                    HandOutLabExecutiveDTO handOutLabExecutiveDTO = getHandOutLabExecutiveDTO(orderId, sampleId);
                    if (Objects.isNull(handOutLabExecutiveDTO)) break;
                    handOut.setCurrentSegment(handOutLabExecutiveDTO.getDeptName());
                    Long measureDeptId = handOutLabExecutiveDTO.getMeasureDeptId();
                    handOut.setAlreadyCertifications(getAlreadyCertificateNum(handOut.getOrderId(), handOut.getSampleId(), measureDeptId));
                    handOut.setRequireCertifications(handOutLabExecutiveDTO.getRequireCertifications());
                    break;
                //检测完状态，分发性质:无，当前检定环节:完成，已出具证书：无，出具证书总数:无
                case SampleStatusEnum.MEASURE_COMPLETE:
                    handOut.setCurrentSegment(CurrentSegmentEnum.COMPLETE);
                    break;
                //超期样品（即检测超期，未在应检完时间检完），分发性质:无，当前检定环节:待分配/具体实验室，已出具证书：查询证书报告表(具体实验室)，出具证书总数：具体实验室
                case SampleStatusEnum.BE_OVERDUE:
                    //待分发的超期
                    if (SampleStatusEnum.TO_HANDOUT.equals(handOut.getSampleStatus())) {
                        handOut.setCurrentSegment(CurrentSegmentEnum.TO_ALLOCATE);
                        break;
                    }
                    HandOutLabExecutiveDTO overLabExecutiveDTO = getHandOutLabExecutiveDTO(orderId, sampleId);
                    if (Objects.isNull(overLabExecutiveDTO)) break;
                    handOut.setCurrentSegment(overLabExecutiveDTO.getDeptName());
                    Long deptId = overLabExecutiveDTO.getMeasureDeptId();
                    handOut.setAlreadyCertifications(getAlreadyCertificateNum(handOut.getOrderId(), handOut.getSampleId(), deptId));
                    handOut.setRequireCertifications(overLabExecutiveDTO.getRequireCertifications());
                    break;
            }
        });
        for (SampleHandOutListResponse record : records) {
            DictCodeUtils.convertDictCodeToName(record);
        }
        return handOutList;
    }

    @Override
    public List<SampleAmountResponse> handOutAmount() {
        SampleHandOutListRequest handOutListRequest = new SampleHandOutListRequest();
        Page<SampleHandOutListResponse> page = getSampleHandOutListResponsePage();
        handOutListRequest.setSampleStatus(SampleStatusEnum.TO_HANDOUT);
        Page<SampleHandOutListResponse> toPage = orderSampleRelationMapper.selectSampleListByStatus(page, handOutListRequest);
        Page<SampleHandOutListResponse> page1 = getSampleHandOutListResponsePage();
        handOutListRequest.setSampleStatus(SampleStatusEnum.IN_MEASURE);
        Page<SampleHandOutListResponse> inPage = orderSampleRelationMapper.selectSampleListByStatus(page1, handOutListRequest);
        Page<SampleHandOutListResponse> page2 = getSampleHandOutListResponsePage();
        handOutListRequest.setSampleStatus(SampleStatusEnum.MEASURE_COMPLETE);
        Page<SampleHandOutListResponse> completePage = orderSampleRelationMapper.selectSampleListByStatus(page2, handOutListRequest);
        Page<SampleHandOutListResponse> page3 = getSampleHandOutListResponsePage();
        handOutListRequest.setSampleStatus(SampleStatusEnum.BE_OVERDUE);
        Page<SampleHandOutListResponse> overPage = orderSampleRelationMapper.selectSampleListByStatus(page3, handOutListRequest);

        SampleAmountResponse toAmount = new SampleAmountResponse(SampleStatusEnum.TO_HANDOUT, toPage.getTotal());
        SampleAmountResponse inAmount = new SampleAmountResponse(SampleStatusEnum.IN_MEASURE, inPage.getTotal());
        SampleAmountResponse completeAmount = new SampleAmountResponse(SampleStatusEnum.MEASURE_COMPLETE, completePage.getTotal());
        SampleAmountResponse overAmount = new SampleAmountResponse(SampleStatusEnum.BE_OVERDUE, overPage.getTotal());
        List<SampleAmountResponse> resultList = new ArrayList<>();
        resultList.add(toAmount);
        resultList.add(inAmount);
        resultList.add(completeAmount);
        resultList.add(overAmount);
        for (SampleAmountResponse sampleAmountResponse : resultList) {
            sampleAmountResponse.setStatusName(dictService.getDictNameByCode(MeterDictCode.SAMPLE_STATUS, sampleAmountResponse.getStatus()));
        }
        return resultList;
    }

    @Override
    public SampleHandOutDetailResponse handOutListDetail(SampleHandOutDetailRequest request) throws Exception{
        //根据样品id和委托书id查询样品、委托书、委托方
        SampleHandOutDetailResponse sampleDetail = orderSampleRelationMapper.selectSampleDetail(request.getOrderId(), request.getSampleId());
        if(Objects.isNull(sampleDetail)){
            throw new BusinessException(BusinessExceptionEnum.NON_EXIST_ORDER_OR_SAMPLE);
        }
        //根据样品id和委托书id查询检定流程、退回信息
        List<MeasureProcessDTO> measureProcessDTOS = labExecutiveInfoMapper.selectExecutiveList(request.getOrderId(), request.getSampleId());
        measureProcessDTOS.forEach(measureProcessDTO -> {
            measureProcessDTO.setMeasureStatusName(dictService.getDictNameByCode(MeterDictEnum.MEASURE_STATUS, measureProcessDTO.getMeasureStatus()));
        });
        List<MeasureSendBackDTO> measureSendBackDTOS = labExecutiveOperateLogMapper.selectExecutiveOperateLogList(request.getOrderId(), request.getSampleId());
        sampleDetail.setMeasureProcessList(measureProcessDTOS);
        sampleDetail.setMeasureSendBackList(measureSendBackDTOS);
        DictCodeUtils.convertDictCodeToName(sampleDetail);
        return sampleDetail;
    }

    @Override
    public List<SampleHandOutInitListResponse> handOutInitList(SampleHandOutInitListRequest handOutInitListRequest) {
        //是否存在样品的实验室检定信息标准模板
        //后续可采用该方式和模板分类方式实现自动分发
        List<SampleHandOutInitListResponse> initListResponses = labExecutiveTemplateInfoMapper.selectExecutiveList(handOutInitListRequest);
        if(!CollectionUtils.isEmpty(initListResponses)){
            return initListResponses;
        }

        if(StringUtils.isEmpty(handOutInitListRequest.getMeasureContent())){
            return new ArrayList<>();
        }
        //根据样品的检定项目去关键字匹配实验室能力信息
        String[] split = handOutInitListRequest.getMeasureContent().split(",");
        List<String> list = Arrays.asList(split);
        //返回列表分发员需要调整，后续不建议采用该方式实现自动分发
        List<SampleHandOutInitListResponse> initListResponseList = organizeMapper.selectListByLabCapacity(list);
        String now = DateUtil.now();
        initListResponseList.forEach(response -> {
            response.setUpdateTime(now);
        });
        return initListResponseList;
    }

    @Override
    @Transactional
    public ReturnDTO handOut(SampleHandOutRequest handOutRequest) {
        Assert.isFalse(Objects.isNull(ShiroKit.getUser()), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        Long orderId = handOutRequest.getOrderId();
        Long sampleId = handOutRequest.getSampleId();
        List<HandOutProcessDTO> measureProcessList = handOutRequest.getMeasureProcessList();
        List<HandOutProcessDTO> sortedList = measureProcessList.stream().sorted(Comparator.comparing(HandOutProcessDTO::getMeasureSequence)).collect(Collectors.toList());
        //检定流程加入实验室记录表
        List<BusinessLabExecutiveInfo> labExecutiveInfos = new ArrayList<>();
        for (int i = 0; i < sortedList.size(); i++) {
            BusinessLabExecutiveInfo labExecutiveInfo = new BusinessLabExecutiveInfo();
            if(0 == i){
                //将第一个置为待分配(负责人可查看)
                labExecutiveInfo.setMeasureStatus(MeasureStatusEnum.TO_ALLOCATE);
            }
            HandOutProcessDTO handOutProcessDTO = sortedList.get(i);
            labExecutiveInfo.setOrderId(orderId);
            labExecutiveInfo.setSampleId(sampleId);
            labExecutiveInfo.setMeasureDeptId(handOutProcessDTO.getMeasureSegmentId());
            labExecutiveInfo.setMeasurePersonId(handOutProcessDTO.getMeasurePersonId());
            labExecutiveInfo.setMeasureSequence(handOutProcessDTO.getMeasureSequence());
            labExecutiveInfo.setIsAuto(0);//默认手动检定
            labExecutiveInfo.setRequireCertifications(handOutProcessDTO.getRequireCertifications());
            labExecutiveInfo.setCreateUser(ShiroKit.getUser().getId());
            labExecutiveInfos.add(labExecutiveInfo);
        }
        //更新样品状态为检测中
        int updateFlag = orderSampleRelationMapper.updateByOrderIdAndSampleId(orderId, sampleId, SampleStatusEnum.IN_MEASURE);
        if(this.saveBatch(labExecutiveInfos) && updateFlag > 0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public Page<SampleLabExecutiveListResponse> deptLabExecutiveListPage(Page<SampleLabExecutiveListResponse> page, SampleLabExecutiveListRequest labExecutiveListRequest) throws Exception{
        //本级部门主管可见本部门的检测
        //根据用户id查询，用户角色中TIPS为director即为主管，取用户的部门id
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });

        Map<String, Object> resultMap = selectDirectDept(user);
        if(CollectionUtils.isEmpty(resultMap) || Objects.isNull(resultMap.get("deptId"))){
            return new Page<>();
        }
        Long deptId = (Long) resultMap.get("deptId");
        String deptName = (String) resultMap.get("deptName");
        //获取部门下的各检测状态列表
        String measureStatus = labExecutiveListRequest.getMeasureStatus();
        Page<SampleLabExecutiveListResponse> resultPage = new Page<>();
        switch (measureStatus) {
            //待检测，查询待分配状态
            //当前检定环节:具体实验室，已出具证书：无，出具证书总数:无
            case MeasureStatusEnum.TO_MEASURE:
                resultPage = labExecutiveInfoMapper.selectListByDeptIdAndStatus(page, labExecutiveListRequest, deptId, MeasureStatusEnum.TO_ALLOCATE, null);
                resultPage.getRecords().forEach(lab -> {
                    lab.setCurrentSegmentId(deptId);
                    lab.setCurrentSegment(deptName);
                });
                break;

            //检测中，查询待检测和检测中
            //当前检定环节:具体实验室，已出具证书：查询证书报告表(检测中，待检测无)，证书总数：具体实验室
            case MeasureStatusEnum.IN_MEASURE:
                List<String> statusList = new ArrayList<>();
                statusList.add(MeasureStatusEnum.TO_MEASURE);
                statusList.add(MeasureStatusEnum.IN_MEASURE);
                resultPage = labExecutiveInfoMapper.selectListByDeptIdAndStatus(page, labExecutiveListRequest, deptId,null, statusList);
                resultPage.getRecords().parallelStream().forEach(lab -> {
                    lab.setCurrentSegmentId(deptId);
                    lab.setCurrentSegment(deptName);
                    //查询证书报告表
                    if(MeasureStatusEnum.IN_MEASURE.equals(lab.getMeasureStatus())){
                        Integer alreadyCertificateNum = getAlreadyCertificateNum(lab.getOrderId(), lab.getSampleId(), deptId);
                        lab.setAlreadyCertifications(alreadyCertificateNum);
                    }
                });
                break;

            //检测完，查询检测完，当前检定环节:其他实验室/检测完，已出具证书：查询证书报告表/无，证书总数：具体实验室/无
            case MeasureStatusEnum.MEASURE_COMPLETE:
                resultPage = labExecutiveInfoMapper.selectListByDeptIdAndStatus(page, labExecutiveListRequest, deptId, MeasureStatusEnum.MEASURE_COMPLETE, null);
                //查询样品检定到的其他实验室或样品检测完成
                enrichLabExecutiveRecords(resultPage);
                break;
        }
        if(!CollectionUtils.isEmpty(resultPage.getRecords())){
            for (SampleLabExecutiveListResponse record : resultPage.getRecords()) {
                DictCodeUtils.convertDictCodeToName(record);
            }
        }
        return resultPage;
    }

    @Override
    public Page<SampleLabExecutiveListResponse> myLabExecutiveListPage(Page<SampleLabExecutiveListResponse> page, SampleLabExecutiveListRequest labExecutiveListRequest) throws Exception{
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        //登录用户id获取计量人员id，实验室检测信息中存储的是计量人员id
        MeterStaff meterStaff = getMeterStaffInfo(user);
//        if(Objects.isNull(meterStaff)) throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_NOT_STAFF);
        if(Objects.isNull(meterStaff)) return new Page<>();
        Long userId = meterStaff.getId();

        String measureStatus = labExecutiveListRequest.getMeasureStatus();
        Page<SampleLabExecutiveListResponse> resultPage = new Page<>();
        switch (measureStatus) {
            //待检测，查询本人待检测状态
            //当前检定环节:具体实验室，已出具证书：无，出具证书总数:无
            case MeasureStatusEnum.TO_MEASURE:
                resultPage = labExecutiveInfoMapper.selectListByUserIdAndStatus(page, labExecutiveListRequest, userId, MeasureStatusEnum.TO_MEASURE);
                resultPage.getRecords().forEach(lab -> {
                    lab.setCurrentSegmentId(lab.getMeasureDeptId());
                    lab.setCurrentSegment(lab.getMeasureDeptName());
                });
                break;

            //检测中，查询本人检测中
            //当前检定环节:具体实验室，已出具证书：查询证书报告表，证书总数：具体实验室
            case MeasureStatusEnum.IN_MEASURE:
                resultPage = labExecutiveInfoMapper.selectListByUserIdAndStatus(page, labExecutiveListRequest, userId, MeasureStatusEnum.IN_MEASURE);
                resultPage.getRecords().forEach(lab -> {
                    lab.setCurrentSegmentId(lab.getMeasureDeptId());
                    lab.setCurrentSegment(lab.getMeasureDeptName());
                    //本实验室在一个流程中若有多次检测，这里的证书信息是多次的总和，已出具的是当前本人的（后续根据需求定义调整）
                    Integer alreadyCertificateNum = getAlreadyCertificateNum(lab.getOrderId(), lab.getSampleId(), lab.getMeasureDeptId());
                    lab.setAlreadyCertifications(alreadyCertificateNum);
                });
                break;

            //检测完，查询本人检测完，当前检定环节:其他实验室/检测完，已出具证书：查询证书报告表/无，证书总数：具体实验室/无
            case MeasureStatusEnum.MEASURE_COMPLETE:
                resultPage = labExecutiveInfoMapper.selectListByUserIdAndStatus(page, labExecutiveListRequest, userId, MeasureStatusEnum.MEASURE_COMPLETE);
                //查询样品检定到的其他实验室或样品检测完成
                enrichLabExecutiveRecords(resultPage);
                break;
        }
        if(!CollectionUtils.isEmpty(resultPage.getRecords())){
            for (SampleLabExecutiveListResponse record : resultPage.getRecords()) {
                DictCodeUtils.convertDictCodeToName(record);
            }
        }
        return resultPage;
    }

    @Override
    public List<SampleAmountResponse> myExecutiveAmount() {
        //登录用户id获取计量人员id，实验室检测信息中存储的是计量人员id
        AuthUser user = ShiroKit.getUser();
        MeterStaff meterStaff = getMeterStaffInfo(user);
//        if(Objects.isNull(meterStaff)) throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_NOT_STAFF);
        if(Objects.isNull(meterStaff)) return new ArrayList<>();
        Long userId = meterStaff.getId();
        Page<SampleLabExecutiveListResponse> page = getSampleLabExecutiveListResponsePage();
        Page<SampleLabExecutiveListResponse> page1 = getSampleLabExecutiveListResponsePage();
        Page<SampleLabExecutiveListResponse> page2 = getSampleLabExecutiveListResponsePage();
        SampleLabExecutiveListRequest labExecutiveListRequest = new SampleLabExecutiveListRequest();
        Page<SampleLabExecutiveListResponse> toPage = labExecutiveInfoMapper.selectListByUserIdAndStatus(page, labExecutiveListRequest, userId, MeasureStatusEnum.TO_MEASURE);
        Page<SampleLabExecutiveListResponse> inPage = labExecutiveInfoMapper.selectListByUserIdAndStatus(page1, labExecutiveListRequest, userId, MeasureStatusEnum.IN_MEASURE);
        Page<SampleLabExecutiveListResponse> completePage = labExecutiveInfoMapper.selectListByUserIdAndStatus(page2, labExecutiveListRequest, userId, MeasureStatusEnum.MEASURE_COMPLETE);
        SampleAmountResponse toAmount = new SampleAmountResponse(MeasureStatusEnum.TO_MEASURE, toPage.getTotal());
        SampleAmountResponse inAmount = new SampleAmountResponse(MeasureStatusEnum.IN_MEASURE, inPage.getTotal());
        SampleAmountResponse completeAmount = new SampleAmountResponse(MeasureStatusEnum.MEASURE_COMPLETE, completePage.getTotal());
        List<SampleAmountResponse> resultList = new ArrayList<>();
        resultList.add(toAmount);
        resultList.add(inAmount);
        resultList.add(completeAmount);
        for (SampleAmountResponse sampleAmountResponse : resultList) {
            sampleAmountResponse.setStatusName(dictService.getDictNameByCode(MeterDictCode.MEASURE_STATUS, sampleAmountResponse.getStatus()));
        }
        return resultList;
    }

    @Override
    public ReturnDTO sampleReceive(List<SampleOperateRequest> requestList) {
        //扫描收入会显示扫进来哪些，检测人员确定要扫描的样品后，调用接口，接口中查询是否在该用户的待检测中有该样品，没有则返回提示信息，有则更新状态
        //该接口前应该有个根据标签查询样品信息的接口（查样品和委托书关联表中最新的委托书的样品列表）
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        //登录用户id获取计量人员id，实验室检测信息中存储的是计量人员id
        MeterStaff meterStaff = getMeterStaffInfo(user);
        if(Objects.isNull(meterStaff)) throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_NOT_STAFF);
        Long userId = meterStaff.getId();

        //查询扫描样品中为该用户待检测中的样品列表
        List<SampleOperateRequest> preList = labExecutiveInfoMapper.selectListForSampleOperate(requestList, userId, MeasureStatusEnum.TO_MEASURE);
        if(CollectionUtils.isEmpty(preList)){
            throw new BusinessException(BusinessExceptionEnum.RECEIVE_SAMPLE_NOT_EXIST);
        }
        int updateFlag = labExecutiveInfoMapper.updateForSampleInMeasureOperate(preList, userId, MeasureStatusEnum.IN_MEASURE);
        if(updateFlag > 0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.RECEIVE_SAMPLE_NOT_EXIST);
    }

    @Override
    @Transactional
    public ReturnDTO sampleExecutiveComplete(List<SampleOperateRequest> requestList) {
        //查询是否在该用户的检测中有该样品，没有则返回提示信息，有则更新检测状态、更新样品状态（判断是否全部实验室检测完成）
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        //登录用户id获取计量人员id，实验室检测信息中存储的是计量人员id
        MeterStaff meterStaff = getMeterStaffInfo(user);
        if(Objects.isNull(meterStaff)) throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_NOT_STAFF);
        Long userId = meterStaff.getId();

        //查询扫描样品中为该用户检测中的样品列表
        List<SampleOperateRequest> preList = labExecutiveInfoMapper.selectListForSampleOperate(requestList, userId, MeasureStatusEnum.IN_MEASURE);
        if(CollectionUtils.isEmpty(preList)){
            throw new BusinessException(BusinessExceptionEnum.COMPLETE_SAMPLE_NOT_EXIST);
        }
        int updateFlag = labExecutiveInfoMapper.updateForSampleMeasureCompleteOperate(preList, userId, MeasureStatusEnum.MEASURE_COMPLETE);
        if(updateFlag > 0){
            preList.forEach(pre -> {
                //是否全部实验室完成，所有实验室无检测完外的其他状态或空才是样品的检测完（有终止状态会把样品状态直接更新为待归还，有退回的状态会从表中删除加入到log表）
                QueryWrapper<BusinessLabExecutiveInfo> wrapper = new QueryWrapper<>();
                wrapper.eq("order_id", pre.getOrderId());
                wrapper.eq("sample_id", pre.getSampleId());
                List<BusinessLabExecutiveInfo> labExecutiveInfos = labExecutiveInfoMapper.selectList(wrapper);//可查到updateFlag更新后的值
                List<BusinessLabExecutiveInfo> unExecutiveInfos = labExecutiveInfos.stream().filter(lab ->
                        StringUtils.isEmpty(lab.getMeasureStatus()) || !StringUtils.equals(MeasureStatusEnum.MEASURE_COMPLETE, lab.getMeasureStatus())
                ).collect(Collectors.toList());
                //全部实验室检测完成
                if(CollectionUtils.isEmpty(unExecutiveInfos)){
                    //更新样品状态为检测完
                    orderSampleRelationMapper.updateByOrderIdAndSampleId(pre.getOrderId(), pre.getSampleId(), SampleStatusEnum.MEASURE_COMPLETE);

                    //委托书中所有样品检测完更新委托书接收状态为检测完成，未检测完的数量为0则表示全部检完
                    updateOrderStatusComplete(pre);

                    //将检测记录加入到实验室检测模板（仅全部为检测完成的才加入到模板，包含终止的不会加入）
                    List<BusinessLabExecutiveTemplateInfo> labList = new ArrayList<>();
                    Long maxNo = labExecutiveTemplateInfoMapper.selectMaxTemplateNo();
                    for (int i = 0; i < labExecutiveInfos.size(); i++) {
                        BusinessLabExecutiveInfo lab = labExecutiveInfos.get(i);
                        BusinessLabExecutiveTemplateInfo templateInfo = getBusinessLabExecutiveTemplateInfo(maxNo, i, lab);
                        labList.add(templateInfo);
                    }
                    if(labExecutiveTemplateInfoService.saveBatch(labList)) log.info("实验室检测记录批量保存为实验室检测模板成功");
                }else {
                    //更新下一个审批的实验室为待分配
                    //注：分发员不可以调整待分配/检测中等有状态的节点（只能调整无状态的）
                    Optional<BusinessLabExecutiveInfo> minSeqLab = labExecutiveInfos.stream().filter(dto ->
                            StringUtils.isEmpty(dto.getMeasureStatus()) /*&& Objects.isNull(dto.getMeasurePersonId())*/
                    ).sorted(Comparator.comparing(BusinessLabExecutiveInfo::getMeasureStatus)).findFirst();
                    if(minSeqLab.isPresent()){
                        BusinessLabExecutiveInfo labExecutiveInfo = minSeqLab.get();
                        labExecutiveInfo.setMeasureStatus(MeasureStatusEnum.TO_ALLOCATE);
                        labExecutiveInfoMapper.updateById(labExecutiveInfo);
                        log.info("更新下一个审批的实验室为待分配成功");
                    }
                }
            });
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.COMPLETE_SAMPLE_NOT_EXIST);
    }

    @Transactional
    public void updateOrderStatusComplete(SampleOperateRequest pre) {
        QueryWrapper<BusinessOrderSampleRelation> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("order_id", pre.getOrderId());
        List<String> statusList = new ArrayList<>();
        statusList.add(SampleStatusEnum.TO_RECEIVE);
        statusList.add(SampleStatusEnum.TO_HANDOUT);
        statusList.add(SampleStatusEnum.IN_MEASURE);
        wrapper1.in("sample_status", statusList);
        //同一事务中可查到更新后的数量
        if(orderSampleRelationMapper.selectCount(wrapper1) == 0){
            BusinessOrder businessOrder = new BusinessOrder();
            businessOrder.setId(pre.getOrderId());
            businessOrder.setStatus(OrderStatusEnum.COMPLETE);
            orderMapper.updateById(businessOrder);
        }
    }

    private BusinessLabExecutiveTemplateInfo getBusinessLabExecutiveTemplateInfo(Long maxNo, int i, BusinessLabExecutiveInfo lab) {
        BusinessLabExecutiveTemplateInfo templateInfo = new BusinessLabExecutiveTemplateInfo();
        String templateCode = NumberGeneratorUtil.getContactNo(PrefixCodeEnum.LAB_EXECUTIVE_TEMPLATE_PREFIX, maxNo + i);
        templateInfo.setTemplateCode(templateCode);
//      templateInfo.setSampleTypeId();
        templateInfo.setSampleId(lab.getSampleId());
        templateInfo.setMeasureDeptId(lab.getMeasureDeptId());
        templateInfo.setMeasurePersonId(lab.getMeasurePersonId());
//      templateInfo.setMeasureItem();
        templateInfo.setExecuteSequence(lab.getMeasureSequence());
//      templateInfo.setCreateUser();
        return templateInfo;
    }

    @Override
    public ReturnDTO updateExecutiveList(UpdateExecutiveListRequest request) {
        //删除前端已删除的ids
        List<UpdateExecutiveListDTO> executiveList = request.getExecutiveList();
        List<Long> ids = executiveList.stream().map(UpdateExecutiveListDTO::getId).filter(Objects::nonNull).collect(Collectors.toList());
        QueryWrapper<BusinessLabExecutiveInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", request.getOrderId());
        wrapper.eq("sample_id", request.getSampleId());
        wrapper.notIn("id", ids);
        //business_lab_executive_info表无id_del字段，为物理删
        this.remove(wrapper);

        //更新已有id的顺序/实验室/人员信息
        List<BusinessLabExecutiveInfo> updateList = new ArrayList<>();
        //新增之前不存在的实验室列表（根据id判断）
        List<BusinessLabExecutiveInfo> addList = new ArrayList<>();
        for (UpdateExecutiveListDTO executiveDTO : executiveList) {
            //待分配状态分发员可更新检定员
            if(StringUtils.isNotEmpty(executiveDTO.getMeasureStatus()) && !MeasureStatusEnum.TO_ALLOCATE.equals(executiveDTO.getMeasureStatus())) continue;
            if(Objects.isNull(executiveDTO.getId())){
                BusinessLabExecutiveInfo labExecutiveInfo = new BusinessLabExecutiveInfo();
                labExecutiveInfo.setId(executiveDTO.getId());
                labExecutiveInfo.setOrderId(request.getOrderId());
                labExecutiveInfo.setSampleId(request.getSampleId());
                labExecutiveInfo.setMeasureDeptId(executiveDTO.getMeasureSegmentId());
                labExecutiveInfo.setMeasurePersonId(executiveDTO.getMeasurePersonId());
                labExecutiveInfo.setMeasureSequence(executiveDTO.getMeasureSequence());
                labExecutiveInfo.setRequireCertifications(executiveDTO.getRequireCertifications());
                addList.add(labExecutiveInfo);
            }else{
                BusinessLabExecutiveInfo labExecutiveInfo = new BusinessLabExecutiveInfo();
                labExecutiveInfo.setId(executiveDTO.getId());
                labExecutiveInfo.setMeasureDeptId(executiveDTO.getMeasureSegmentId());
                labExecutiveInfo.setMeasurePersonId(executiveDTO.getMeasurePersonId());
                labExecutiveInfo.setMeasureSequence(executiveDTO.getMeasureSequence());
                labExecutiveInfo.setRequireCertifications(executiveDTO.getRequireCertifications());
                updateList.add(labExecutiveInfo);
            }
        }
        this.updateBatchById(updateList);
        this.saveBatch(addList);
        return ReturnUtil.success();
    }

    @Override
    public ReturnDTO updateExecutive(UpdateExecutiveRequest request) {
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        MeterStaff meterStaff = getMeterStaffInfo(user);
        if(Objects.isNull(meterStaff)) throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_NOT_STAFF);
        Long userId = meterStaff.getId();

        if(request.getMeasurePersonId() != userId){
            throw new BusinessException(BusinessExceptionEnum.CANNOT_CHANGE_MEASURE_INFO);
        }
        BusinessLabExecutiveInfo executiveInfo = new BusinessLabExecutiveInfo();
        executiveInfo.setId(request.getId());
        executiveInfo.setRequireCertifications(request.getRequireCertifications());
        if(labExecutiveInfoMapper.updateById(executiveInfo) > 0){
            return ReturnUtil.success();
        }
        log.info("更新实验室应出具证书信息失败，主键id：{}", request.getId());
        return ReturnUtil.failed();
    }

    @Override
    public ExecutiveDetailResponse executiveDetail(ExecutiveDetailRequest request) throws Exception{
        //根据样品id和委托书id查询样品、委托书、委托方
        SampleHandOutDetailResponse sampleDetail = orderSampleRelationMapper.selectSampleDetail(request.getOrderId(), request.getSampleId());
        if(Objects.isNull(sampleDetail)){
            throw new BusinessException(BusinessExceptionEnum.NON_EXIST_ORDER_OR_SAMPLE);
        }
        ExecutiveDetailResponse detailResponse = ConvertUtils.sourceToTarget(sampleDetail, ExecutiveDetailResponse.class);
        //根据样品id和委托书id查询检定流程
        List<MeasureProcessDTO> measureProcessDTOS = labExecutiveInfoMapper.selectExecutiveList(request.getOrderId(), request.getSampleId());
        detailResponse.setMeasureProcessList(measureProcessDTOS);
        DictCodeUtils.convertDictCodeToName(detailResponse);
        return detailResponse;
    }

    @Override
    @Transactional
    public ReturnDTO sampleExecutiveSendBack(ExecutiveSendBackRequest request) {
        //查询是否在该用户的检测中有该样品，没有则返回提示信息，有则更新检测状态、更新样品状态（判断是否全部实验室检测完成）
        AuthUser user = ShiroKit.getUser();
        Assert.isFalse(Objects.isNull(user), () -> {
            throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_ACQUIRE_FAILED);
        });
        MeterStaff meterStaff = getMeterStaffInfo(user);
        if(Objects.isNull(meterStaff)) throw new BusinessException(BusinessExceptionEnum.LOGIN_USER_NOT_STAFF);
        Long userId = meterStaff.getId();

        //删除实验室检测列表中退回数据
        int deleteFlag = labExecutiveInfoMapper.deleteById(request.getId());
        //退回操作记录表中增加数据
        BusinessLabExecutiveOperateLog operateLog = getBusinessLabExecutiveOperateLog(request, user, userId);
        int insertFlag = labExecutiveOperateLogMapper.insert(operateLog);
        if(deleteFlag > 0 && insertFlag > 0){
            //退回后会将下一个要执行的实验室检测状态更新为待分配，将后面的实验室顺序变更为连续（都进行减1）
            //更新所有状态为空的实验室检测的序号为当前减1
            int seqUpdateFlag = labExecutiveInfoMapper.updateForSendBack(request.getOrderId(), request.getSampleId());
            //更新所有状态为空的实验室检测中序号最小的记录的状态为待分配
            Long id = labExecutiveInfoMapper.selectMinSeq(request.getOrderId(), request.getSampleId());
            //仅分发了一个实验室检测或无实验室可分配的情况
            if(seqUpdateFlag <= 0 && Objects.isNull(id)){
                //将样品状态变为待分发
                orderSampleRelationMapper.updateByOrderIdAndSampleId(request.getOrderId(), request.getSampleId(), SampleStatusEnum.TO_HANDOUT);
                return ReturnUtil.success();
            }
            BusinessLabExecutiveInfo info = new BusinessLabExecutiveInfo();
            info.setId(id);
            info.setMeasureStatus(MeasureStatusEnum.TO_ALLOCATE);
            int statusUpdateFlag = labExecutiveInfoMapper.updateById(info);
            if(seqUpdateFlag > 0 && statusUpdateFlag > 0) return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    @Override
    public ReturnDTO allocateStaff(SampleAllocateRequest sampleAllocateRequest) {
        BusinessLabExecutiveInfo labExecutiveInfo = new BusinessLabExecutiveInfo();
        labExecutiveInfo.setId(sampleAllocateRequest.getId());
        labExecutiveInfo.setMeasurePersonId(sampleAllocateRequest.getMeasurePersonId());
        labExecutiveInfo.setMeasureStatus(MeasureStatusEnum.TO_MEASURE);
        labExecutiveInfo.setRequireCertifications(sampleAllocateRequest.getRequireCertifications());
        if(labExecutiveInfoMapper.updateById(labExecutiveInfo) > 0){
            return ReturnUtil.success();
        }
        throw new BusinessException(BusinessExceptionEnum.HANDLE_FAILED);
    }

    private Page<SampleHandOutListResponse> getSampleHandOutListResponsePage() {
        Page<SampleHandOutListResponse> page = PageFactory.defaultPage();
        page.setCurrent(1);
        page.setSize(1);
        return page;
    }

    private Page<SampleLabExecutiveListResponse> getSampleLabExecutiveListResponsePage() {
        Page<SampleLabExecutiveListResponse> page = PageFactory.defaultPage();
        page.setCurrent(1);
        page.setSize(1);
        return page;
    }

    private QueryWrapper<BusinessLabExecutiveOperateLog> getOperateLogWrapper(SampleHandOutListResponse handOut) {
        QueryWrapper<BusinessLabExecutiveOperateLog> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", handOut.getOrderId());
        wrapper.eq("sample_id", handOut.getSampleId());
        wrapper.eq("measure_status", MeasureStatusEnum.SEND_BACK);
        return wrapper;
    }

    private QueryWrapper<BusinessCertificateReport> getCertificateReportWrapper(Long orderId, Long sampleId, Long deptId) {
        QueryWrapper<BusinessCertificateReport> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", orderId);
        wrapper.eq("sample_id", sampleId);
        wrapper.eq("measure_dept_id", deptId);
        wrapper.eq("approval_status", ApprovalStatusEnum.PASSED);
        return wrapper;
    }

    private MeterStaff getMeterStaffInfo(AuthUser user) {
        String account = user.getAccount();
        QueryWrapper<MeterStaff> wrapper = new QueryWrapper<>();
        wrapper.eq("account", account);
        return staffMapper.selectOne(wrapper);
    }

    private HandOutLabExecutiveDTO getHandOutLabExecutiveDTO(Long orderId, Long sampleId) {
        List<HandOutLabExecutiveDTO> labExecutiveList = labExecutiveInfoMapper.selectListByInMeasureStatus(orderId, sampleId);
        if (CollectionUtils.isEmpty(labExecutiveList)) {
            log.info("任务分发-检测中状态不存在当前进行检测的实验室，orderId：{}，sampleId：{}", orderId, sampleId);
            return null;
        }
        HandOutLabExecutiveDTO handOutLabExecutiveDTO = labExecutiveList.get(0);
        return handOutLabExecutiveDTO;
    }

    private Integer getAlreadyCertificateNum(Long orderId, Long sampleId, Long measureDeptId) {
        Long aLong = certificateReportMapper.selectCount(getCertificateReportWrapper(orderId, sampleId, measureDeptId));
        return aLong.intValue();
    }

    private void enrichLabExecutiveRecords(Page<SampleLabExecutiveListResponse> resultPage) {
        resultPage.getRecords().parallelStream().forEach(lab -> {
            List<HandOutLabExecutiveDTO> labExecutiveList = labExecutiveInfoMapper.selectListByInMeasureStatus(lab.getOrderId(), lab.getSampleId());
            //未在进行中的实验室则为检测完成（可能存在终止的情况，也算为检测完成）
            if (CollectionUtils.isEmpty(labExecutiveList)) {
                lab.setCurrentSegment(CurrentSegmentEnum.COMPLETE);
            } else {
                HandOutLabExecutiveDTO dto = labExecutiveList.get(0);
                lab.setCurrentSegment(dto.getDeptName());
                Integer alreadyCertificateNum = getAlreadyCertificateNum(lab.getOrderId(), lab.getSampleId(), dto.getMeasureDeptId());
                lab.setAlreadyCertifications(alreadyCertificateNum);
                lab.setRequireCertifications(dto.getRequireCertifications());
            }
        });
    }

    private Map<String, Object> selectDirectDept(AuthUser user) {
        Map<String, Object> resultMap = SqlRunner.db().selectOne(
                "SELECT su.DEPT_ID as deptId, sd.SIMPLE_NAME AS deptName FROM sys_role sr " +
                        "JOIN sys_ru_relation srr ON sr.ID = srr.ROLEID " +
                        "JOIN sys_user su ON srr.USERID = su.ID " +
                        "JOIN sys_dept sd ON su.DEPT_ID = sd.ID " +
                        "WHERE su.ID = {0}" +
                        "AND sr.TIPS = {1}", String.valueOf(user.getId()), "director");
        return resultMap;
    }

    private BusinessLabExecutiveOperateLog getBusinessLabExecutiveOperateLog(ExecutiveSendBackRequest request, AuthUser user, Long userId) {
        BusinessLabExecutiveOperateLog operateLog = new BusinessLabExecutiveOperateLog();
        operateLog.setOrderId(request.getOrderId());
        operateLog.setSampleId(request.getSampleId());
        operateLog.setMeasureDeptId(request.getMeasureSegmentId());
        operateLog.setMeasurePersonId(request.getMeasurePersonId());
        operateLog.setOperatePersonId(userId);
        operateLog.setOperatePersonName(user.getName());
        operateLog.setMeasureStatus(MeasureStatusEnum.SEND_BACK);
        operateLog.setOperateReason(request.getOperateReason());
        return operateLog;
    }

}
