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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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 digital.laboratory.platform.common.mybatis.security.service.DLPUser;
import digital.laboratory.platform.imr.dto.DepositDTO;
import digital.laboratory.platform.imr.dto.IconDTO;
import digital.laboratory.platform.imr.dto.InRepositoryDTO;
import digital.laboratory.platform.imr.entity.*;
import digital.laboratory.platform.imr.enums.DrugMaterialStatus;
import digital.laboratory.platform.imr.feign.TransferFeignService;
import digital.laboratory.platform.imr.feign.dto.UpdateHolderDTO;
import digital.laboratory.platform.imr.mapper.*;
import digital.laboratory.platform.imr.service.DrugMaterialInfoService;
import digital.laboratory.platform.imr.service.SamplePutInStorageService;
import digital.laboratory.platform.imr.service.SampleStorageService;
import digital.laboratory.platform.imr.vo.InboundRecordVO;
import digital.laboratory.platform.imr.vo.OutSampleVO;
import digital.laboratory.platform.imr.vo.RepositorySampleVO;
import digital.laboratory.platform.imr.vo.SampleTableVO;
import digital.laboratory.platform.sys.entity.CellAndStoreSupplyData;
import digital.laboratory.platform.sys.feign.RemoteCabinetService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class SamplePutInStorageServiceImpl implements SamplePutInStorageService {


    private final RemoteCabinetService cabinetService;

    private final SampleInboundAndOutboundTableMapper tableMapper;

    private final SampleInboundRecordMapper recordMapper;

    private final SampleStorageMapper storageMapper;

    private final SampleStorageService sampleStorageService;

    private final TransferFeignService transferFeignService;

    private final CabinetOpeningRecordMapper openingRecordMapper;

    private final DrugMaterialInfoService drugMaterialInfoService;

    private static Map<String, Set<String>> tempSampleInMap = new ConcurrentHashMap<>();



    /**
     * 销毁预警查询接口
     * @param page
     * @param qw
     * @return
     */
    @Override
    public IPage<RepositorySampleVO> getDestructionVO(Page<SampleStorage> page, QueryWrapper<SampleStorage> qw) {

        IPage<RepositorySampleVO> sampleVOList = storageMapper.getSampleVOList(page, qw);
        for (RepositorySampleVO sampleVo:sampleVOList.getRecords()) {
            sampleVo.setDescribe("样本存储期限快满");
            String eventName = "";
            //entrustment/hairJob/sewageJob
            if (sampleVo.getSource().equals("entrustment")){
                //委托
                eventName = storageMapper.getEntrustmentName(sampleVo.getSampleId());
            }else if (sampleVo.getSource().equals("hairJob")) {
                //毛发
                eventName = storageMapper.getHairJobName(sampleVo.getSampleId());
            }else if (sampleVo.getSource().equals("sewageJob")) {
                //污水
                eventName = storageMapper.getSewageJobName(sampleVo.getSampleId());
            }else if (sampleVo.getSource().contains("Event")) {
                //内部录入
                eventName = storageMapper.getEventName(sampleVo.getSampleId());
            }else {
                //特征分析
                eventName = storageMapper.getFeatureName(sampleVo.getSampleId());
            }
            //其他来源
            sampleVo.setEventName(eventName);
        }
        return sampleVOList;
    }

    /**
     * 出入库样本详情
     * 样本信息+出入库登记表信息
     * @param id
     * @return
     */
    @Override
    public RepositorySampleVO getSampleDetailed(String id) {

        SampleStorage sampleStorage = storageMapper.selectById(id);
        if(sampleStorage==null){
            throw new RuntimeException("当前数据不存在,请重试");
        }
        //获取样本详情信息
        RepositorySampleVO sampleVO = storageMapper.getSampleDetailed(sampleStorage.getId());

        String eventName = "";
        //entrustment/hairJob/sewageJob
        if (sampleVO.getSource().equals("entrustment")){
            //委托
            eventName = storageMapper.getEntrustmentName(sampleVO.getSampleId());
        }else if (sampleVO.getSource().equals("hairJob")) {
            //毛发
            eventName = storageMapper.getHairJobName(sampleVO.getSampleId());
        }else if (sampleVO.getSource().equals("sewageJob")) {
            //污水
            eventName = storageMapper.getSewageJobName(sampleVO.getSampleId());
        }else if (sampleVO.getSource().contains("Event")) {
            //内部录入
            eventName = storageMapper.getEventName(sampleVO.getSampleId());
        }else {
            //特征分析
            eventName = storageMapper.getFeatureName(sampleVO.getSampleId());
        }
        //其他来源--内部录入
        sampleVO.setEventName(eventName);

        //出入库登记表
        List<SampleTableVO> table =  tableMapper.getTableVO(sampleStorage.getSampleId());

        sampleVO.setTableVO(table);

        return sampleVO ;
    }

    @Override
    public IPage<RepositorySampleVO> getSampleVOList(Page<SampleStorage> page, QueryWrapper<SampleStorage> orderByDesc) {
        IPage<RepositorySampleVO> sampleVOList = storageMapper.getSampleVOList(page, orderByDesc);

        List<RepositorySampleVO> records = sampleVOList.getRecords();

        for (RepositorySampleVO sampleVO : records) {

            String eventName = "";
            //entrustment/hairJob/sewageJob/internal
            if (sampleVO.getSource().equals("entrustment")){
                //委托
                eventName = storageMapper.getEntrustmentName(sampleVO.getSampleId());
            }else if (sampleVO.getSource().equals("hairJob")) {
                //毛发
                eventName = storageMapper.getHairJobName(sampleVO.getSampleId());
            }else if (sampleVO.getSource().equals("sewageJob")) {
                //污水
                eventName = storageMapper.getSewageJobName(sampleVO.getSampleId());
            } else if (sampleVO.getSource().contains("Event")) {
                //内部录入
                eventName = storageMapper.getEventName(sampleVO.getSampleId());
            }else {
                //特征分析
                eventName = storageMapper.getFeatureName(sampleVO.getSampleId());
            }
            //其他来源
            sampleVO.setEventName(eventName);
        }

        return sampleVOList;
    }

    @Override
    public IPage<InboundRecordVO> inboundRecord(Page<SampleInboundRecord> page, QueryWrapper<SampleInboundRecord> qw) {

        IPage<InboundRecordVO> inboundRecordVOIPage = recordMapper.inboundRecord(page, qw);
        List<InboundRecordVO> records = inboundRecordVOIPage.getRecords();
        for (InboundRecordVO vo : records) {
            String eventName = "";
            //entrustment/hairJob/sewageJob
            if (vo.getSource().equals("entrustment")){
                //委托
                eventName = storageMapper.getEntrustmentName(vo.getSampleId());
            }else if (vo.getSource().equals("hairJob")) {
                //毛发
                eventName = storageMapper.getHairJobName(vo.getSampleId());
            }else if (vo.getSource().equals("sewageJob")) {
                //污水
                eventName = storageMapper.getSewageJobName(vo.getSampleId());
            }
            else if (vo.getSource().contains("Event")) {
                //内部录入
                eventName = storageMapper.getEventName(vo.getSampleId());
            }else {
                //特征分析
                eventName = storageMapper.getFeatureName(vo.getSampleId());
            }
            //其他来源
            vo.setEventName(eventName);
        }

        return inboundRecordVOIPage;
    }



    /**
     * 扫描编号获取信息
     * @param sampleNo
     * @return
     */
    @Override
    public List<OutSampleVO> getSampleListByNo(String sampleNo) {

        //样本编号或检材编号
        List<OutSampleVO> vo = storageMapper.getSampleListByNo(sampleNo);

//       if (vo.isEmpty()) {
//           throw new RuntimeException(String.format("编号为"+sampleNo+"的样本不存在请重试"));
//       }
        return vo;
    }



    /** 2...
     * 仓库录入样本检材(无仓库样本表格)
     * 录入单位为样本(盒子取消)
     * (不考虑流转质量)
     * @param sampleNos
     * @param dlpUser
     * @return
     */
    @Override
    @Transactional
    public List<OutSampleVO> sampleEntryRepository(List<String> sampleNos, DLPUser dlpUser) {

        ArrayList<OutSampleVO> sampleVOS = new ArrayList<>();

        //验证样本编号的准确
        for (String sampleNo:sampleNos) {
            OutSampleVO sampleVO = storageMapper.getSampleByNo(sampleNo);
            if (sampleVO==null){
                throw new RuntimeException(String.format("编号为"+sampleNo+"的样本不存在请重试"));
            }
            SampleStorage sampleStorage = storageMapper.selectById(sampleVO.getSampleId());
            //已经录入到关联表;待存放状态
            if(sampleStorage!=null){
                if(sampleStorage.getStatus()==1||sampleStorage.getStatus()==2){
                    throw new RuntimeException(String.format("编号为"+sampleNo+"的样本已录入"));
                } else if (sampleStorage.getStatus()==3) {//已出库;现在是重新入库
                    //重新入库是更新
                }

            }else {
                //新录入仓库样本(添加操作)
                SampleStorage storage = new SampleStorage();
                storage.setId(IdWorker.get32UUID().toUpperCase());
                storage.setStatus(1);
                storage.setDepositorId(sampleVO.getHolder());//当前持有人变成入库人
                storage.setInRepositoryDate(LocalDateTime.now());//入库时间
                if (sampleVO.getCategory().equals("生物特性物证")){
                    //存储时间为一年
                    storage.setStorageDate(LocalDateTime.now().plusYears(1));
                }else {
                    //毒品和其他存储时间为长期(100年)
                    storage.setStorageDate(LocalDateTime.now().plusYears(100));
                }
                storage.setSampleId(sampleVO.getSampleId());//样本id
                storage.setEarlyWarning(0);//创建默认未到"销毁"
                storage.setName(sampleVO.getName());
                storage.setSampleType(sampleVO.getSampleType());//样本类型
                //数据存储
                storageMapper.insert(storage);
            }

            /*-- 远程调用
                1.入库了这个当前持有人是变成仓库还是检材管理员

                2.流转记录要跟新
                3.样本状态
             */
            //2.
            transferFeignService.addTransferByInbound(sampleVO.getSampleId(),dlpUser.getId());

            //1.
            UpdateHolderDTO updateHolderDTO = new UpdateHolderDTO();
            updateHolderDTO.setHolder(dlpUser.getId());
            updateHolderDTO.setSampleId(sampleVO.getSampleId());
            transferFeignService.updateSampleHolder(updateHolderDTO);



            //入库记录
            SampleInboundRecord record = new SampleInboundRecord();
            record.setId(IdWorker.get32UUID().toUpperCase());
            record.setWarehousingPersonId(sampleVO.getHolder());
            record.setWarehousingDate(LocalDateTime.now());
            record.setImAdministrators(dlpUser.getId());
            record.setSampleId(sampleVO.getSampleId());
            record.setName(sampleVO.getName());
            record.setRemarks("检材入库");
            recordMapper.insert(record);

            //3.b_sample样本状态为已入库
            transferFeignService.updateStatus(sampleVO.getSampleId(),2);

            sampleVOS.add(storageMapper.getSampleByNo(sampleNo));
        }
        //
        return sampleVOS;

    }

    /**
     * 第三种样本入库
     * (考虑流转质量)
     * @param sample
     * @param dlpUser
     * @return
     */

    @Override
    @Transactional
    public List<OutSampleVO> sampleInRepository(List<InRepositoryDTO> sample, DLPUser dlpUser) {

        ArrayList<OutSampleVO> sampleVOS = new ArrayList<>();
        for (InRepositoryDTO dto: sample) {
            //先通过样本编号查询出这个样本的基本信息(重点是获取到id)
            OutSampleVO sampleVO = storageMapper.getSampleById(dto.getSampleNo());
            if (sampleVO==null){
                throw new RuntimeException("样本不存在请重试");
            }
            if (sampleVO.getSampleStatus()!=1 && sampleVO.getSampleStatus()!=14){//这里增加1和14的状态14是检验完成
                throw new RuntimeException(String.format("编号为"+sampleVO.getSampleNo()+"的样本当前状态不是入库状态"));
            }
            QueryWrapper<SampleStorage> wrapper = new QueryWrapper<>();
            wrapper.eq("sample_id",sampleVO.getId());
            SampleStorage sampleStorage = storageMapper.selectOne(wrapper);
            //已经录入到关联表;待存放状态
            if(sampleStorage!=null){
                if(sampleStorage.getStatus()==1||sampleStorage.getStatus()==2){
                    throw new RuntimeException(String.format("编号为"+dto.getSampleNo()+"的样本已录入"));
                } else if (sampleStorage.getStatus()==3) {//已出库;现在是重新入库
                    //重新入库是更新(二次入库)
                    sampleStorage.setInRepositoryDate(LocalDateTime.now());
                    sampleStorage.setRecipientId(null);
                    sampleStorage.setDepositorId(sampleVO.getHolder());
                    sampleStorage.setStatus(1);
                    sampleStorage.setOutRepositoryDate(null);
                    storageMapper.updateById(sampleStorage);

                   /* UpdateWrapper<SampleStorage> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.eq("sample_id", sampleVO.getSampleId());
                    updateWrapper.set("in_repository_date",LocalDateTime.now());//入库时间
                    updateWrapper.set("recipient_id",sampleVO.getHolder());//入库人
                    updateWrapper.set("depositor_id",null);//删除领取人--这里把鉴定了设置为领取人;
                    updateWrapper.set("out_repository_date",null);//删除出库时间;
                    updateWrapper.set("status",1);//待存放
                    storageMapper.update(null,updateWrapper);*/
                }

            }else {
                //新录入仓库样本(添加操作)
                SampleStorage storage = new SampleStorage();
                storage.setId(IdWorker.get32UUID().toUpperCase());
                storage.setStatus(1);//入库待存放
                storage.setDepositorId(sampleVO.getHolder());//当前持有人变成入库人
                storage.setInRepositoryDate(LocalDateTime.now());//入库时间
                if (sampleVO.getCategory().equals("生物特性物证")){
                    //存储时间为一年
                    storage.setStorageDate(LocalDateTime.now().plusYears(1));
                }else {
                    //毒品和其他存储时间为长期(100年)
                    storage.setStorageDate(LocalDateTime.now().plusYears(100));
                }
                storage.setSampleId(sampleVO.getId());//样本id
                storage.setEarlyWarning(0);//创建默认未到"销毁"
                storage.setUnit(dto.getUnit());//单位
                storage.setQuality(dto.getQuality());//入库时的质量
                storage.setName(sampleVO.getName());
                storage.setSampleType(sampleVO.getSampleType());//样本类型
                //数据存储
                storageMapper.insert(storage);
            }

            /*-- 远程调用
                1.入库了这个当前持有人是变成仓库还是检材管理员
                2.流转记录要跟新(但是当前入库时的样本质量怎么保证)
                3.b_sample样本状态为已入库
             */
            //2.入库记录流转记录表(考虑质量)
            if (dto.getUnit()!=null && dto.getQuality()!=null){
                transferFeignService.addTransferByIn(sampleVO.getId(), dto.getUnit(), dto.getQuality(),dlpUser.getId());
            }
            //不考虑质量
            transferFeignService.addTransferByInbound(sampleVO.getId(),dlpUser.getId());

            //1.入库更新当前持有人(检材仓库)
            UpdateHolderDTO updateHolderDTO = new UpdateHolderDTO();
            updateHolderDTO.setHolder(dlpUser.getId());
            updateHolderDTO.setSampleId(sampleVO.getId());
            transferFeignService.updateSampleHolder(updateHolderDTO);//远程调用

            //更新出入库登记表(这里因为只有入库,所以就创建部分数据;入库一定是添加数据)
            SampleInboundAndOutboundTable table = new SampleInboundAndOutboundTable();
            table.setId(IdWorker.get32UUID().toUpperCase());
            table.setImAdministrators(dlpUser.getId());
            table.setRecipient(sampleVO.getHolder());//持有人变入库人
            table.setRemarks("检材入库");
            table.setWarehousingDate(LocalDateTime.now());//入库时间
            table.setSampleId(sampleVO.getId());
            table.setInboundSupervisor(dto.getSupervisor());//入库监督人
            tableMapper.insert(table);
            //新出入库登记表

            //入库记录
            SampleInboundRecord record = new SampleInboundRecord();
            record.setId(IdWorker.get32UUID().toUpperCase());
            record.setWarehousingPersonId(sampleVO.getHolder());//入库人
            record.setWarehousingDate(LocalDateTime.now());
            record.setImAdministrators(dlpUser.getId());
            record.setSampleId(sampleVO.getId());
            record.setName(sampleVO.getName());
            record.setRemarks("检材入库");
            recordMapper.insert(record);

            //3.b_sample样本状态为已入库
            transferFeignService.updateStatus(sampleVO.getId(),2);

            sampleVOS.add(storageMapper.getSampleById(dto.getSampleNo()));
        }

        tempSampleInMap.remove(dlpUser.getId());
        log.warn("remove temporary put in storage sample, current map size: {}", tempSampleInMap.size());
        return sampleVOS;
    }


    /**
     * 检材存放
     * @param dto
     * @return
     */
    @Override
    @GlobalTransactional
    public List<OutSampleVO> sampleDepositRepository(DepositDTO dto) {
        /**
         * 优化接口效率，不在循环中操作数据库，提前获取需要的数据，转成map操作
         */
        List<String> ids = dto.getIds();
        Map<String, SampleStorage> sampleStorageMap = storageMapper
                .selectList(Wrappers.<SampleStorage>lambdaQuery().in(SampleStorage::getId, ids))
                .stream().collect(Collectors.toMap(SampleStorage::getId, Function.identity()));

        ArrayList<String> sampleIds = new ArrayList<>();
        List<OutSampleVO> outSampleVOS = new ArrayList<>();
        List<SampleStorage> sampleStorageList = ids.stream().map(id -> {
            //这里的id是样本存储表的id
            SampleStorage sampleStorage = sampleStorageMap.get(id);
            if (sampleStorage == null) {
                throw new RuntimeException(String.format("当前id为 %s 样本存储数据为空", id));
            }
            if (sampleStorage.getStatus() != 1) {
                throw new RuntimeException(String.format("当前id为 %s 样本不是待存放的状态", id));
            }
            sampleStorage.setStorageLocation(dto.getStorageLocation());
            sampleStorage.setStatus(2);//入库已经存放
            sampleStorage.setStorageCellId(dto.getCellId());//存储格子id
            sampleStorage.setRoomNo(dto.getRoomNo());//房间号
            sampleStorage.setBoxId(dto.getBoxId());
            sampleStorage.setCabinetName(dto.getCabinetName());//柜子名称
            sampleStorage.setBuildingLv(dto.getBuildingLv());//楼层

            //添加样本id
            sampleIds.add(sampleStorage.getSampleId());
            return sampleStorage;
        }).collect(Collectors.toList());
        // 批量更新
        sampleStorageService.updateBatchById(sampleStorageList);
        // 根据检材的类型做对应的处理
        if (dto.getType() == 0) {
            sampleStorageList.forEach(sampleStorage -> {
                OutSampleVO sampleVO = storageMapper.getSampleById(sampleStorage.getSampleId());
                sampleVO.setStorageLocation(dto.getStorageLocation());
                outSampleVOS.add(sampleVO);
            });
        } else {
            sampleStorageList.forEach(sampleStorage ->
                outSampleVOS.add(drugMaterialInfoService.drugMaterialToOutSampleVO(sampleStorage, sampleStorage.getSampleId()))
            );
            //3.毒品库中的毒品检材信息样本状态为已入库
            drugMaterialInfoService.update(Wrappers.<DrugMaterialInfo>lambdaUpdate().in(DrugMaterialInfo::getId, sampleIds)
                    .set(DrugMaterialInfo::getStatus, DrugMaterialStatus.FINISH_INBOUND.getStatus()));
        }
        //去除最后一个“,”
        //String str = sampleIds.substring(0,sampleIds.lastIndexOf(","));

        CellAndStoreSupplyData cellAndStoreSupplyData = new CellAndStoreSupplyData();
        cellAndStoreSupplyData.setCellId(dto.getCellId());//格子id
        cellAndStoreSupplyData.setCellStatus(dto.getCellStatus());//格子状态
        cellAndStoreSupplyData.setStoreSupplyList(sampleIds);//样本id
        /*
        柜子新接口
         */
        //cabinetService.updateCabinet(dto.getCellId(),str,"1");
        ArrayList<CellAndStoreSupplyData> supplyData = new ArrayList<>();
        supplyData.add(cellAndStoreSupplyData);
        cabinetService.takeOrSaveGoodsFromCabinet(supplyData,1);
        return outSampleVOS;
    }

    //流转模块角标总和
    @Override
    public IconDTO getTransferIconCount(String id) {

        Long transferCount = storageMapper.getTransferCount(id);

        Long witnessCount = storageMapper.getWitnessCount(id);

        Long count = transferCount + witnessCount;
        IconDTO transfer = null;
        if(count!=0){
            transfer = new IconDTO(count, 5, "transfer");
        }
        return transfer;
    }

    //修改质量
    @Override
    public void updateSampleQuality(String sampleId, double sampleQuality) {
        //先查询出能不能修改

        openingRecordMapper.updateSampleQuality(sampleId,sampleQuality);
    }

    /**
     * 临时处理样本入库
     * @param vos
     * @param user
     */
    @Override
    public void temporaryProcessSampleIn(List<OutSampleVO> vos, DLPUser user) {
        String userId = user.getId();
        for (OutSampleVO vo : vos) {
            if (tempSampleInMap.containsKey(userId)) {
                Set<String> sampleIds = tempSampleInMap.get(userId);
                if (vo.getIsPutIn().equals(1)) {
                    sampleIds.add(vo.getId());
                } else {
                    sampleIds.remove(vo.getId());
                }
                tempSampleInMap.put(userId, sampleIds);
            } else {
                Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
                synchronizedSet.add(vo.getId());
                tempSampleInMap.put(userId, synchronizedSet);
            }
        }
    }

    /**
     * 一个检材入库时的可选检材列表
     */
    @Override
    public Map<String, List<OutSampleVO>> choseSampleList(String keyWords) {
        List<OutSampleVO> voList = storageMapper.choseSampleList();
        Map<String, List<OutSampleVO>> resultMap = new HashMap<>();
        if (CollUtil.isNotEmpty(tempSampleInMap)) {
            Set<String> idSet = Collections.synchronizedSet(new HashSet<>());
            tempSampleInMap.forEach((k, v) -> {
                idSet.addAll(v);
            });
            log.info("void ==== {}", idSet.toString());
            List<OutSampleVO> inSampleList = new ArrayList<>();
            List<OutSampleVO> waitInSampleList = new ArrayList<>();
            for (OutSampleVO outSampleVO : voList) {
                if (idSet.contains(outSampleVO.getId())) {
                    inSampleList.add(outSampleVO);
                } else {
                    waitInSampleList.add(outSampleVO);
                }
            }
            if (StrUtil.isNotBlank(keyWords)) {
                waitInSampleList = waitInSampleList.stream()
                        .filter(sampleVo -> sampleVo.getSampleNo().contains(keyWords) || sampleVo.getName().contains(keyWords))
                        .collect(Collectors.toList());
            }
            resultMap.put("putInStorage", inSampleList);
            resultMap.put("waitPutInStorage", waitInSampleList);
            return resultMap;
        }
        if (StrUtil.isNotBlank(keyWords)) {
            voList = voList.stream()
                    .filter(sampleVo -> sampleVo.getSampleNo().contains(keyWords) || sampleVo.getName().contains(keyWords))
                    .collect(Collectors.toList());
        }
        resultMap.put("waitPutInStorage", voList);
        return resultMap;
    }

}
