package com.kcim.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult;
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kcim.common.constants.Constant;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.constants.RedisKeyConstant;
import com.kcim.common.enums.ErrorCodeEnum;
import com.kcim.common.enums.MatchTypeEnum;
import com.kcim.common.exception.CostException;
import com.kcim.common.token.RedisUtil;
import com.kcim.common.util.BeanUtil;
import com.kcim.common.util.MatchTextComparatorUtil;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.UserContext;
import com.kcim.common.util.excel.ExcelStyleUtil;
import com.kcim.common.util.excel.entity.ItemImportEntity;
import com.kcim.common.util.excel.handler.MedServiceItemTypeHandler;
import com.kcim.dao.model.*;
import com.kcim.dao.repository.*;
import com.kcim.service.CenterService;
import com.kcim.service.DrugService;
import com.kcim.service.ItemService;
import com.kcim.service.MaterialService;
import com.kcim.vo.CommonParameterVo;
import com.kcim.vo.DictDataVo;
import com.kcim.vo.ItemMapVo;
import com.kcim.vo.KCClassVo;
import com.kcim.web.reponse.AutoMatchResponse;
import com.kcim.web.reponse.MatchCountResponse;
import com.kcim.web.request.ItemMapRequest;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.kcim.common.constants.ParameterConstant.AUTO_MATCH_PERCENT;

/**
 * @program: CostAccount
 * @description: 收费项目管理接口实现类
 * @author: Wang.YS
 * @create: 2023-11-10 14:19
 **/
@Service("ItemService")
@Slf4j
@AllArgsConstructor
public class ItemServiceImpl implements ItemService {
    /**
     * 医疗服务项目数据库交互
     */
    ItemRepository repository;
    /**
     * 标准项目字典
     */
    StandItemRepository standItemRepository;
    /**
     * 中台对外接口服务
     */
    CenterService centerService;
    /**
     * 人员分类字典
     */
    EmpCostTypeRepository empCostTypeRepository;
    /**
     * 设备字典
     */
    EquipmentRepository equipmentRepository;
    /**
     * 空间成本字典
     */
    SpaceRepository spaceRepository;
    /**
     * 药品字典
     */
    DrugRepository drugRepository;
    /**
     * 材料字典
     */
    MaterialRepository materialRepository;
    /**
     * 医疗服务项目与参与人员对照
     */
    ItemEmpMapRepository itemEmpMapRepository;
    /**
     * 医疗服务项目与使用设备对照
     */
    ItemEquipmentMapRepository itemEquipmentMapRepository;
    /**
     * 医疗服务项目与使用空间对照
     */
    ItemSpaceMapRepository itemSpaceMapRepository;
    /**
     * 医疗服务项目与不计价药品材料对照
     */
    ItemNoValuationDrugMaterialMapRepository itemNoValuationDrugMaterialMapRepository;
    /**
     * 医疗服务项目与计价药品材料对照
     */
    ItemValuationDrugMaterialMapRepository itemValuationDrugMaterialMapRepository;


    RedisUtil redisUtil;

    HistoryMatchRepository historyMatchRepository;


    /**
     * 获取收费项目列表
     *
     * @param current  当前页
     * @param pageSize 页容量
     * @param name     项目名称
     * @param type     显示未对照 0全部 1未对照
     * @return 列表
     */
    @Override
    public Object getItemList(Integer current, Integer pageSize, String name, Integer type) {
        Page<Item> page = repository.getPage(current, pageSize, name, type);
        List<Item> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return new PageUtils(new ArrayList<>(), NumberConstant.ZERO, pageSize, current);
        }
        List<KCClassVo> kcClass = centerService.getKCClass();

        DictDataVo centerDict = centerService.getCenterDict(Constant.MED_SERVICE_ITEM_TYPE);
        List<DictDataVo> dataVoList = centerDict.getDataVoList();
        Map<String, String> typeNameMap = dataVoList.stream().collect(Collectors.toMap(DictDataVo::getCode, DictDataVo::getName, (a, b) -> b));

        if (!CollectionUtils.isEmpty(kcClass)) {
            Map<String, String> map = kcClass.stream().collect(Collectors.toMap(KCClassVo::getCode, KCClassVo::getLevelName, (a, b) -> b));
            records.forEach(record -> record.setKcCodeName(map.get(record.getKcCode())));
        }
        records.forEach(record -> record.setItemTypeName(typeNameMap.get(record.getItemType())));
        //获取参与人员
        List<ItemEmpMap> empMapRepositoryList = itemEmpMapRepository.getList();
//        Map<String, List<ItemEmpMap>> empMapGroup = new HashMap<>();
        Map<String,Map<String, List<ItemEmpMap>>> empMapGroup = new HashMap<>();
        if (!CollectionUtils.isEmpty(empMapRepositoryList)) {
            //获了人员类别字典
            List<EmpCostType> list = empCostTypeRepository.getList();
            Map<String, String> map = list.stream().collect(Collectors.toMap(EmpCostType::getCostTypeCode, EmpCostType::getCostTypeName, (a, b) -> b));
            //添加人员类别回显字段
            empMapRepositoryList.forEach(f -> f.setEmpTypeCodeName(map.get(f.getEmpTypeCode())));
            //按科室代码分组
            Map<String, List<ItemEmpMap>> collect = empMapRepositoryList.stream().collect(Collectors.groupingBy(ItemEmpMap::getDepartmentCode));
            //再按项目代码进行分组  组装
            collect.forEach((k,v)->{
                empMapGroup.put(k,v.stream().collect(Collectors.groupingBy(ItemEmpMap::getItemCode)));
            });
        }
        //获取使用空间
        List<ItemSpaceMap> spaceMapList = itemSpaceMapRepository.getList();
        Map<String,Map<String, List<ItemSpaceMap>>> spaceMapGroup = new HashMap<>();
        if (!CollectionUtils.isEmpty(spaceMapList)) {
            List<Space> list = spaceRepository.getList();
            Map<String, String> map = list.stream().collect(Collectors.toMap(Space::getCode, Space::getName, (a, b) -> b));
            spaceMapList.forEach(spaceMap -> spaceMap.setSpaceCodeName(map.get(spaceMap.getSpaceCode())));

            //按科室代码分组
            Map<String, List<ItemSpaceMap>> collect = spaceMapList.stream().collect(Collectors.groupingBy(ItemSpaceMap::getDepartmentCode));
            //再按项目代码进行分组  组装
            collect.forEach((k,v)->{
                spaceMapGroup.put(k,v.stream().collect(Collectors.groupingBy(ItemSpaceMap::getItemCode)));
            });
        }
        //获取使用设备对照
        List<ItemEquipmentMap> equipmentMapList = itemEquipmentMapRepository.getList();
        Map<String,Map<String, List<ItemEquipmentMap>>> equipmentMapGroup = new HashMap<>();
        if (!CollectionUtils.isEmpty(equipmentMapList)) {
            List<Equipment> list = equipmentRepository.getList();
            Map<String, String> map = list.stream().collect(Collectors.toMap(Equipment::getCode, Equipment::getName, (a, b) -> b));
            equipmentMapList.forEach(equipmentMap -> equipmentMap.setEquipmentCodeName(map.get(equipmentMap.getEquipmentCode())));
            //按科室代码分组
            Map<String, List<ItemEquipmentMap>> collect = equipmentMapList.stream().collect(Collectors.groupingBy(ItemEquipmentMap::getDepartmentCode));
            //再按项目代码进行分组  组装
            collect.forEach((k,v)->{
                equipmentMapGroup.put(k,v.stream().collect(Collectors.groupingBy(ItemEquipmentMap::getItemCode)));
            });
        }
        //计价药材
        List<ItemValuationDrugMaterialMap> itemValuationDrugMaterialList = itemValuationDrugMaterialMapRepository.getList();
//        Map<String, List<ItemValuationDrugMaterialMap>> itemValuationDrugMaterialGroup = new HashMap<>();
        Map<String,Map<String, List<ItemValuationDrugMaterialMap>>> itemValuationDrugMaterialGroup = new HashMap<>();
        if (!CollectionUtils.isEmpty(itemValuationDrugMaterialList)) {
            //按科室代码分组
            Map<String, List<ItemValuationDrugMaterialMap>> collect = itemValuationDrugMaterialList.stream().collect(Collectors.groupingBy(ItemValuationDrugMaterialMap::getDepartmentCode));
            //再按项目代码进行分组  组装
            collect.forEach((k,v)->{
                itemValuationDrugMaterialGroup.put(k,v.stream().collect(Collectors.groupingBy(ItemValuationDrugMaterialMap::getItemCode)));
            });
//            itemValuationDrugMaterialGroup = itemValuationDrugMaterialList.stream().collect(Collectors.groupingBy(ItemValuationDrugMaterialMap::getItemCode));

        }

        //不计价药材
//        Map<String, List<ItemNoValuationDrugMaterialMap>> itemNoValuationDrugMaterialGroup = new HashMap<>();
        Map<String,Map<String, List<ItemNoValuationDrugMaterialMap>>> itemNoValuationDrugMaterialGroup = new HashMap<>();
        List<ItemNoValuationDrugMaterialMap> itemNoValuationDrugMaterialList = itemNoValuationDrugMaterialMapRepository.getList();
        if (!CollectionUtils.isEmpty(itemNoValuationDrugMaterialList)) {
            //按科室代码分组
            Map<String, List<ItemNoValuationDrugMaterialMap>> collect = itemNoValuationDrugMaterialList.stream().collect(Collectors.groupingBy(ItemNoValuationDrugMaterialMap::getDepartmentCode));
            //再按项目代码进行分组  组装
            collect.forEach((k,v)->{
                itemNoValuationDrugMaterialGroup.put(k,v.stream().collect(Collectors.groupingBy(ItemNoValuationDrugMaterialMap::getItemCode)));
            });
//            itemNoValuationDrugMaterialGroup = itemNoValuationDrugMaterialList.stream().collect(Collectors.groupingBy(ItemNoValuationDrugMaterialMap::getItemCode));

        }
        Map<String, List<Item>> collect = records.stream().collect(Collectors.groupingBy(Item::getDepartmentCode));
        List<Item> returnResult = new ArrayList<>();
        collect.forEach((k,v)->{
            Map<String, List<ItemEmpMap>> itemEmpMap = empMapGroup.get(k);
            Map<String, List<ItemEquipmentMap>> equipmentMap = equipmentMapGroup.get(k);
            Map<String, List<ItemSpaceMap>> spaceMap = spaceMapGroup.get(k);
            Map<String, List<ItemValuationDrugMaterialMap>> itemValuationMap = itemValuationDrugMaterialGroup.get(k);
            Map<String, List<ItemNoValuationDrugMaterialMap>> itemNoValuationMap = itemNoValuationDrugMaterialGroup.get(k);
            v.forEach(f->{
                if(!CollectionUtils.isEmpty(itemEmpMap)){
                    f.setEmpMaps(itemEmpMap.get(f.getCode()));
                }
                if(!CollectionUtils.isEmpty(equipmentMap)){
                    f.setEquipmentMaps(equipmentMap.get(f.getCode()));
                }
                if(!CollectionUtils.isEmpty(spaceMap)){
                    f.setSpaceMaps(spaceMap.get(f.getCode()));
                }
                if(!CollectionUtils.isEmpty(itemValuationMap)){
                    f.setValuation(itemValuationMap.get(f.getCode()));
                }
                if(!CollectionUtils.isEmpty(itemNoValuationMap)){
                    f.setNoValuation(itemNoValuationMap.get(f.getCode()));
                }
            });
            returnResult.addAll(v);
        });

//
//        for (Item record : records) {
//            record.setEmpMaps(empMapGroup.get(record.getCode()));
//            record.setEquipmentMaps(equipmentMapGroup.get(record.getCode()));
//            record.setSpaceMaps(spaceMapGroup.get(record.getCode()));
//            record.setValuation(itemValuationDrugMaterialGroup.get(record.getCode()));
//            record.setNoValuation(itemNoValuationDrugMaterialGroup.get(record.getCode()));
//        }


        return new PageUtils(returnResult, Math.toIntExact(page.getTotal()), pageSize, current);
    }

    /**
     * 新增收费项目
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public void addItem(Item request) {
        if(Objects.isNull(request.getDepartmentCode())){
            throw new CostException(ErrorCodeEnum.DEPARTMENT_NOT_EXIST);
        }
        List<Item> byCode = repository.getByCode(request.getCode(),request.getDepartmentCode());
        if (!CollectionUtils.isEmpty(byCode)) {
            throw new CostException("当前科室收费项目代码已存在，请修改后再保存");
        }
        request.setHospId(UserContext.getHospId());
        request.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        request.setCreateTime(new Date());
        repository.save(request);
    }

    /**
     * 编辑收费项目
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public void editItem(Item request) {
        Integer id = request.getId();
        if (id == null) {
            throw new CostException("编辑时主键必填");
        }
        if(Objects.isNull(request.getDepartmentCode())){
            throw new CostException(ErrorCodeEnum.DEPARTMENT_NOT_EXIST);
        }
        Item item = repository.getById(id);
        Item oneByCode = repository.getOneByCode(request.getCode(),request.getDepartmentCode());
        if (Objects.nonNull(item)) {
            if (Objects.isNull(oneByCode) || oneByCode.getId().equals(id)) {
                BeanUtil.convertObj(request, item);
                item.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
                item.setUpdateTime(new Date());
                repository.updateById(item);
            } else {
                throw new CostException("当前科室收费项目代码已存在，请修改后再保存");
            }
        }
    }

    /**
     * 删除收费项目
     *
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    public void deleteItem(Integer id) {
        repository.deleteItem(id);
    }

    /**
     * 导出收费项目模版
     *
     * @param response 出参
     * @return 出参
     */
    @SneakyThrows
    @Override
    public Object exportItem(HttpServletResponse response) {
        try {
            //配置excel 文件信息
            ExportParams params = new ExportParams();

            params.setTitle("说明：1、为了保证成功导入，请勿修改模板格式\n" +
                    "      2、项目类别填对应的收费类型名称，如：诊察费、检查费、床位费\n" +
                    "      3、参与人员、使用设备、使用空间填写格式为：人事分类1*人数1*执行时间1|人事分类2*人数2*执行时间2\n" +
                    "      4、不计价药品、不计价材料、计价药品、计价材料填写格式为：项目代码1*项目名称1*项目数量1|项目代码2*项目名称2*项目数量2\n" +
                    "      5、项目分类填：医技项目/医师项目");
            //设置导出样式
            params.setStyle(ExcelStyleUtil.class);
            //设置sheetName
            params.setSheetName("收费项目");
            DictDataVo centerDict = centerService.getCenterDict(Constant.MED_SERVICE_ITEM_TYPE);
            List<DictDataVo> dataVoList = centerDict.getDataVoList();
            params.setDictHandler(new MedServiceItemTypeHandler(dataVoList));

//            FileOutputStream outputStream = new FileOutputStream("E:\\收费项目导入模版.xlsx");
            Workbook workbook = ExcelExportUtil.exportExcel(params, ItemImportEntity.class, new ArrayList<>());
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel");
            String fileName = "收费项目导入模版";
            response.setHeader("Content-Disposition", URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
//            workbook.write(outputStream);
//            outputStream.close();
            workbook.close();
            log.info("导出文件：{}", fileName);
        } catch (FileNotFoundException e) {
            throw new CostException(e.getMessage());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return response.getOutputStream();
    }

    /**
     * 导入收费项目
     *
     * @param file 导入文件
     */
    @Override
    @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
    @SneakyThrows
    public void importItem(MultipartFile file) {
//        try {
        if (ObjectUtils.isEmpty(file) || file.getSize() == 0) {
            throw new CostException("未获取到导入的excel文件内容");
        }
        log.info("接收到文件：{}", file.getOriginalFilename());
        // 参数1：文件流
        InputStream stream = file.getInputStream();
        // 参数2：导入类型
        ImportParams params = new ImportParams();
        //校验Excel 去掉空行
        params.setNeedVerify(true);
        IExcelVerifyHandler<ItemImportEntity> handler = val -> {
            if (StringUtils.isEmpty(val.getCode())) {
                return new ExcelVerifyHandlerResult(false, "收费项目代码不能为空");
            }
            if (StringUtils.isEmpty(val.getName())) {
                return new ExcelVerifyHandlerResult(false, "收费项目名称不能为空");
            }
            if (StringUtils.isEmpty(val.getDepartmentCode())) {
                return new ExcelVerifyHandlerResult(false, "科室代码不能为空");
            }
            if (StringUtils.isEmpty(val.getDepartmentName())) {
                return new ExcelVerifyHandlerResult(false, "科室名称不能为空");
            }
            return new ExcelVerifyHandlerResult(true);
        };
        params.setVerifyHandler(handler);
        // 标题占用多少行
        params.setTitleRows(1);
        // 头部属性占用多少行
        params.setHeadRows(1);
        DictDataVo centerDict = centerService.getCenterDict(Constant.MED_SERVICE_ITEM_TYPE);
        List<DictDataVo> dataVoList = centerDict.getDataVoList();
        params.setDictHandler(new MedServiceItemTypeHandler(dataVoList));
        List<ItemImportEntity> itemImportEntities = ExcelImportUtil.importExcel(stream, ItemImportEntity.class, params);
        if (!CollectionUtils.isEmpty(itemImportEntities)) {

            //人员类别
            List<EmpCostType> empCostTypes = empCostTypeRepository.getList();
            if (CollectionUtils.isEmpty(empCostTypes)) {
                log.error("未维护人员类别，请先维护人员类别数据");
                throw new CostException("未维护人员类别，请先维护人员类别数据");
            }
            Map<String, String> empCostMap = empCostTypes.stream().collect(Collectors.toMap(EmpCostType::getCostTypeName, EmpCostType::getCostTypeCode, (a, b) -> b));
            //设备成本
//            List<Equipment> equipmentList = equipmentRepository.getList();
//            if (CollectionUtils.isEmpty(equipmentList)) {
//                log.error("未维护设备成本，请先维护设备成本数据");
//                throw new CostException("未维护设备成本，请先维护设备成本数据");
//            }
//            Map<String, String> equipmentMap = equipmentList.stream().collect(Collectors.toMap(Equipment::getCode, Equipment::getName, (a, b) -> b));
            //空间成本
            List<Space> spaces = spaceRepository.getList();
            if (CollectionUtils.isEmpty(spaces)) {
                log.error("未维护空间成本字典，请先维护空间成本字典数据");
                throw new CostException("未维护空间成本字典，请先维护空间成本字典数据");
            }
            Map<String, String> spaceMap = spaces.stream().collect(Collectors.toMap(Space::getName, Space::getCode, (a, b) -> b));
//                //药品成本管理
//                List<Drug> drugs = drugRepository.getList();
//                if(CollectionUtils.isEmpty(drugs)){
//                    log.error("未维护药品成本字典，请先维护药品成本字典数据");
//                    throw new CostException("未维护药品成本字典，请先维护药品成本字典数据");
//                }
//                Map<String,String> drugMap = drugs.stream().collect(Collectors.toMap(Drug::getName, Drug::getCode, (a, b) -> b));
//
//                List<Material> materials = materialRepository.getList();
//                if(CollectionUtils.isEmpty(materials)){
//                    log.error("未维护材料成本字典，请先维护材料成本字典数据");
//                    throw new CostException("未维护材料成本字典，请先维护材料成本字典数据");
//                }
//                Map<String,String> materialMap = materials.stream().collect(Collectors.toMap(Material::getName, Material::getCode, (a, b) -> b));

            List<Item> saveList = new ArrayList<>();
            Item ItemDict = new Item();
            ItemDict.setHospId(UserContext.getHospId());
            ItemDict.setCreateTime(new Date());
            ItemDict.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));

            List<ItemEmpMap> empSaveList = new ArrayList<>();
            List<ItemEquipmentMap> equipmentSaveList = new ArrayList<>();
            List<ItemSpaceMap> spaceSaveList = new ArrayList<>();
            List<ItemNoValuationDrugMaterialMap> noValuationDrugMaterialSaveList = new ArrayList<>();
            List<ItemValuationDrugMaterialMap> valuationDrugMaterialSaveList = new ArrayList<>();

            for (ItemImportEntity entity : itemImportEntities) {
                Item item = BeanUtil.convertObj(ItemDict, Item.class);
                item.setDepartmentCode(entity.getDepartmentCode());
                item.setDepartmentName(entity.getDepartmentName());
                item.setCode(entity.getCode());
                item.setName(entity.getName());
                item.setNationalCode(entity.getNationalCode());
                item.setType(entity.getType());
                item.setPrice(entity.getPrice());
                item.setItemType(entity.getItemType());
                saveList.add(item);
                //处理参与人员
                String emp = entity.getEmp();
                if (!StringUtils.isEmpty(emp)) {
                    List<ItemEmpMap> empSplit = getEmpSplit(item.getCode(), emp, empCostMap,item.getDepartmentCode());
                    empSaveList.addAll(empSplit);
                }
                //处理使用设备
                String equipment = entity.getEquipment();
                if (!StringUtils.isEmpty(equipment)) {
                    List<ItemEquipmentMap> equipmentSplit = getEquipmentSplit(item.getCode(), equipment,item.getDepartmentCode());
                    equipmentSaveList.addAll(equipmentSplit);
                }
                //处理使用空间
                String space = entity.getSpace();
                if (!StringUtils.isEmpty(space)) {
                    List<ItemSpaceMap> spaceSplit = getSpaceSplit(item.getCode(), space, spaceMap,item.getDepartmentCode());
                    spaceSaveList.addAll(spaceSplit);
                }
                //处理不计价药品
                String noValuationDrug = entity.getNoValuationDrug();
                if (!StringUtils.isEmpty(noValuationDrug)) {
                    List<ItemNoValuationDrugMaterialMap> noValuationDrugSplit = noValuationSplit(item.getCode(), noValuationDrug, NumberConstant.ONE,item.getDepartmentCode());
                    noValuationDrugMaterialSaveList.addAll(noValuationDrugSplit);
                }
                //处理不计价材料
                String noValuationMaterial = entity.getNoValuationMaterial();
                if (!StringUtils.isEmpty(noValuationMaterial)) {
                    List<ItemNoValuationDrugMaterialMap> noValuationMaterialSplit = noValuationSplit(item.getCode(), noValuationMaterial, NumberConstant.TWO, item.getDepartmentCode());
                    noValuationDrugMaterialSaveList.addAll(noValuationMaterialSplit);
                }

                //处理计价药品
                String valuationDrug = entity.getValuationDrug();
                if (!StringUtils.isEmpty(valuationDrug)) {
                    List<ItemValuationDrugMaterialMap> valuationDrugSplit = valuationSplit(item.getCode(), valuationDrug, NumberConstant.ONE,item.getDepartmentCode());
                    valuationDrugMaterialSaveList.addAll(valuationDrugSplit);
                }
                //处理计价材料
                String valuationMaterial = entity.getValuationMaterial();
                if (!StringUtils.isEmpty(valuationMaterial)) {
                    List<ItemValuationDrugMaterialMap> valuationMaterialSplit = valuationSplit(item.getCode(), valuationMaterial, NumberConstant.TWO, item.getDepartmentCode());
                    valuationDrugMaterialSaveList.addAll(valuationMaterialSplit);
                }
            }
            if (!CollectionUtils.isEmpty(saveList)) {
                check();
                repository.saveBatch(saveList, 100);
                if (!CollectionUtils.isEmpty(empSaveList)) {
                    itemEmpMapRepository.saveBatch(empSaveList);
                }
                if (!CollectionUtils.isEmpty(equipmentSaveList)) {
                    itemEquipmentMapRepository.saveBatch(equipmentSaveList);
                }
                if (!CollectionUtils.isEmpty(spaceSaveList)) {
                    itemSpaceMapRepository.saveBatch(spaceSaveList);
                }
                if (!CollectionUtils.isEmpty(noValuationDrugMaterialSaveList)) {
                    itemNoValuationDrugMaterialMapRepository.saveBatch(noValuationDrugMaterialSaveList);
                }
                if (!CollectionUtils.isEmpty(valuationDrugMaterialSaveList)) {
                    itemValuationDrugMaterialMapRepository.saveBatch(valuationDrugMaterialSaveList);
                }
            }
        }
//        } catch (Exception e) {
//            throw new CostException(e.getMessage());
//        }
    }

    private List<ItemValuationDrugMaterialMap> valuationSplit(String code, String valuation, Integer type, String departmentCode) {
        List<ItemValuationDrugMaterialMap> list = new ArrayList<>();
        if (valuation.contains("|")) {
            //有多个
            List<String> split = StrUtil.split(valuation, "|");
            for (String s : split) {
                convertValuationItem(code, list, s, type,departmentCode);
            }
        } else {
            //只有一个
            convertValuationItem(code, list, valuation, type, departmentCode);
        }
        return list;
    }

    private void convertValuationItem(String code, List<ItemValuationDrugMaterialMap> list, String s, Integer type, String departmentCode) {
        List<String> split1 = StrUtil.split(s, "*");
        if (split1.size() < 2) {
            if (type.equals(NumberConstant.ONE)) {
                log.error("当前" + code + "项目计价药品导入信息有误");
                throw new CostException("当前" + code + "项目计价药品导入信息有误");
            } else {
                log.error("当前" + code + "项目计价材料导入信息有误");
                throw new CostException("当前" + code + "项目计价材料导入信息有误");
            }

        }
        if (type.equals(NumberConstant.ONE)) {
            log.error("当前" + code + "项目计价药品导入信息有误");
            if (StringUtils.isEmpty(split1.get(0))) {
                throw new CostException("当前" + code + "项目计价药品项目代码导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(1))) {
                throw new CostException("当前" + code + "项目计价药品项目名称导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(2))) {
                throw new CostException("当前" + code + "项目计价药品项目数量导入信息有误");
            }
        } else {
            log.error("当前" + code + "项目计价材料导入信息有误");
            if (StringUtils.isEmpty(split1.get(0))) {
                throw new CostException("当前" + code + "项目计价材料项目代码导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(1))) {
                throw new CostException("当前" + code + "项目计价材料项目名称导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(2))) {
                throw new CostException("当前" + code + "项目计价材料项目数量导入信息有误");
            }
        }
        ItemValuationDrugMaterialMap vo = new ItemValuationDrugMaterialMap();
        vo.setCode(split1.get(0));
        vo.setName(split1.get(1));
        vo.setNum(Integer.parseInt(split1.get(2)));
        vo.setType(type);
        vo.setItemCode(code);
        vo.setDepartmentCode(departmentCode);
        vo.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        vo.setCreateTime(new Date());
        vo.setHospId(UserContext.getHospId());
        list.add(vo);
    }

    private List<ItemNoValuationDrugMaterialMap> noValuationSplit(String code, String noValuation, Integer type, String departmentCode) {
        List<ItemNoValuationDrugMaterialMap> list = new ArrayList<>();
        if (noValuation.contains("|")) {
            //有多个
            List<String> split = StrUtil.split(noValuation, "|");
            for (String s : split) {
                convertNoValuationItem(code, list, s, type,departmentCode);
            }
        } else {
            //只有一个
            convertNoValuationItem(code, list, noValuation, type, departmentCode);
        }
        return list;
    }

    private void convertNoValuationItem(String code, List<ItemNoValuationDrugMaterialMap> list, String s, Integer type, String departmentCode) {
        List<String> split1 = StrUtil.split(s, "*");
        if (split1.size() < 2) {
            if (type.equals(NumberConstant.ONE)) {
                log.error("当前" + code + "项目不计价药品导入信息有误");
                throw new CostException("当前" + code + "项目不计价药品导入信息有误");
            } else {
                log.error("当前" + code + "项目不计价材料导入信息有误");
                throw new CostException("当前" + code + "项目不计价材料导入信息有误");
            }

        }
        if (type.equals(NumberConstant.ONE)) {
            log.error("当前" + code + "项目不计价药品导入信息有误");
            if (StringUtils.isEmpty(split1.get(0))) {
                throw new CostException("当前" + code + "项目不计价药品项目代码导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(1))) {
                throw new CostException("当前" + code + "项目不计价药品项目名称导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(2))) {
                throw new CostException("当前" + code + "项目不计价药品数量导入信息有误");
            }
        } else {
            log.error("当前" + code + "项目不计价材料导入信息有误");
            if (StringUtils.isEmpty(split1.get(0))) {
                throw new CostException("当前" + code + "项目不计价材料项目代码导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(1))) {
                throw new CostException("当前" + code + "项目不计价材料项目名称导入信息有误");
            }
            if (StringUtils.isEmpty(split1.get(2))) {
                throw new CostException("当前" + code + "项目不计价材料数量导入信息有误");
            }
        }


        ItemNoValuationDrugMaterialMap vo = new ItemNoValuationDrugMaterialMap();
        vo.setCode(split1.get(0));
        vo.setName(split1.get(1));
        vo.setNum(Integer.parseInt(split1.get(2)));
        vo.setType(type);
        vo.setItemCode(code);
        vo.setDepartmentCode(departmentCode);
        vo.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        vo.setCreateTime(new Date());
        vo.setHospId(UserContext.getHospId());
        list.add(vo);
    }

    private List<ItemSpaceMap> getSpaceSplit(String code, String space, Map<String, String> spaceMap, String departmentCode) {
        List<ItemSpaceMap> list = new ArrayList<>();
        if (space.contains("|")) {
            //有多个
            List<String> split = StrUtil.split(space, "|");
            for (String s : split) {
                convertSpaceItem(code, spaceMap, list, s,departmentCode);
            }
        } else {
            //只有一个
            convertSpaceItem(code, spaceMap, list, space, departmentCode);
        }
        return list;
    }

    private void convertSpaceItem(String code, Map<String, String> spaceMap, List<ItemSpaceMap> list, String s, String departmentCode) {
        List<String> split1 = StrUtil.split(s, "*");
        if (split1.size() < 2) {
            log.error("当前" + code + "项目使用空间导入信息有误");
            throw new CostException("当前" + code + "项目使用空间导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(0))) {
            throw new CostException("当前" + code + "项目使用空间空间代码导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(1))) {
            throw new CostException("当前" + code + "项目使用空间数量导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(2))) {
            throw new CostException("当前" + code + "项目使用空间执行时间导入信息有误");
        }
        ItemSpaceMap vo = new ItemSpaceMap();
        vo.setSpaceCode(spaceMap.get(split1.get(0)));
        vo.setNum(new BigDecimal(split1.get(1)));
        vo.setExecuteTime(new BigDecimal(split1.get(2)));
        vo.setItemCode(code);
        vo.setDepartmentCode(departmentCode);
        vo.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        vo.setCreateTime(new Date());
        vo.setHospId(UserContext.getHospId());
        list.add(vo);
    }

    private List<ItemEquipmentMap> getEquipmentSplit(String code, String equipment,  String departmentCode) {
        List<ItemEquipmentMap> list = new ArrayList<>();
        if (equipment.contains("|")) {
            //有多个
            List<String> split = StrUtil.split(equipment, "|");
            for (String s : split) {
                convertEquipment(code,  list, s,departmentCode);
            }
        } else {
            //只有一个
            convertEquipment(code, list, equipment, departmentCode);
        }
        return list;
    }

    private void convertEquipment(String code, List<ItemEquipmentMap> list, String s, String departmentCode) {
        List<String> split1 = StrUtil.split(s, "*");
        if (split1.size() < 2) {
            log.error("当前" + code + "项目使用设备导入信息有误");
            throw new CostException("当前" + code + "项目使用设备导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(0))) {
            throw new CostException("当前" + code + "项目使用设备设备代码导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(1))) {
            throw new CostException("当前" + code + "项目使用设备数量导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(2))) {
            throw new CostException("当前" + code + "项目使用设备执行时间导入信息有误");
        }
        ItemEquipmentMap vo = new ItemEquipmentMap();
        vo.setEquipmentCode(split1.get(0));
        vo.setNum(new BigDecimal(split1.get(1)));
        vo.setExecuteTime(new BigDecimal(split1.get(2)));
        vo.setItemCode(code);
        vo.setDepartmentCode(departmentCode);
        vo.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        vo.setCreateTime(new Date());
        vo.setHospId(UserContext.getHospId());



        list.add(vo);
    }

    private List<ItemEmpMap> getEmpSplit(String code, String emp,  Map<String, String> empCostMap,String departmentCode) {
        List<ItemEmpMap> list = new ArrayList<>();
        if (emp.contains("|")) {
            //有多个
            List<String> split = StrUtil.split(emp, "|");
            for (String s : split) {
                convertEmpItem(code, empCostMap, list, s,departmentCode);
            }
        } else {
            //只有一个
            convertEmpItem(code, empCostMap, list, emp,departmentCode);
        }
        return list;
    }

    private void convertEmpItem(String code, Map<String, String> empCostMap, List<ItemEmpMap> list, String s, String departmentCode) {
        List<String> split1 = StrUtil.split(s, "*");
        if (split1.size() < 2) {
            log.error("当前" + code + "项目参与人员导入信息有误");
            throw new CostException("当前" + code + "项目参与人员导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(0))) {
            throw new CostException("当前" + code + "项目参与人员人事分类导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(1))) {
            throw new CostException("当前" + code + "项目参与人员人数导入信息有误");
        }
        if (StringUtils.isEmpty(split1.get(2))) {
            throw new CostException("当前" + code + "项目参与人员执行时间导入信息有误");
        }
        ItemEmpMap vo = new ItemEmpMap();
//        System.out.println(code+"---"+split1);
        vo.setEmpTypeCode(empCostMap.get(split1.get(0)));
        vo.setNum(new BigDecimal(split1.get(1)));
        vo.setExecuteTime(new BigDecimal(split1.get(2)));
        vo.setItemCode(code);
        vo.setDepartmentCode(departmentCode);
        vo.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        vo.setCreateTime(new Date());
        vo.setHospId(UserContext.getHospId());
        list.add(vo);
    }

    private void check() {
        List<Item> list = repository.getList();
        if (!CollectionUtils.isEmpty(list)) {
            repository.removeList(list);
            List<String> collect = list.stream().map(Item::getCode).collect(Collectors.toList());

            //移除参与人员
            itemEmpMapRepository.removeByItemCode(collect);
            //移除设备
            itemEquipmentMapRepository.removeByItemCode(collect);
            //移除使用空间
            itemSpaceMapRepository.removeByItemCode(collect);
            //移除不计价药材
            itemNoValuationDrugMaterialMapRepository.removeByItemCode(collect);
            //称除计价药材
            itemValuationDrugMaterialMapRepository.removeByItemCode(collect);


        }
    }

    /**
     *
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void matchItemAndStandItem(String progressKey) {
        //ITEM_BATCH_MATCH
        //获取病种字典
        List<StandItem> list = standItemRepository.getList();
        if (CollectionUtils.isEmpty(list)) {
            throw new CostException("当前院区未添加标准项目字典，添先添加标准项目再进行对照");
        }
        List<Item> items = repository.getList();
        if (CollectionUtils.isEmpty(items)) {
            throw new CostException("当前院区未添加收费项目，添先添加收费项目再进行对照");
        }
        Map<String, StandItem> map = list.stream().collect(Collectors.toMap(StandItem::getNationalCode, type -> type, (a, b) -> b));
        List<Item> collect = items.stream().filter(f -> StringUtils.isEmpty(f.getStandItemCode())).collect(Collectors.toList());
        redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, 0 + "/" + items.size());

        if (!CollectionUtils.isEmpty(collect)) {
            for (int i = 0; i < collect.size(); i++) {
                Item item = collect.get(i);
                String nationalCode = item.getNationalCode();
                if (!StringUtils.isEmpty(nationalCode)) {
                    StandItem standItem = map.get(nationalCode);
                    if (Objects.nonNull(standItem)) {
                        item.setStandItemCode(standItem.getCode());
                        item.setStandItemName(standItem.getName());
                        item.setKcCode(standItem.getKcClassCode());
                    }
                }
                redisUtil.set(RedisKeyConstant.PROGRESS + progressKey, i + "/" + items.size());
            }
            repository.updateBatchById(collect);
        }
        redisUtil.del(RedisKeyConstant.PROGRESS + progressKey);
    }

    /**
     *
     */
    @Override
    public Object getStandItemDict(String name) {
        return standItemRepository.getList(name);

    }

    @Override
    public List<OrderItemMap> getItemDict(String name) {
        List<Item> list = repository.getList(name);
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<OrderItemMap> returnList = new ArrayList<>();
        for (Item item : list) {
            OrderItemMap orderItemMap = new OrderItemMap();
            orderItemMap.setItemCode(item.getCode());
            orderItemMap.setItemName(item.getName());
            orderItemMap.setItemType(String.valueOf(NumberConstant.THREE));
            returnList.add(orderItemMap);
        }
        return returnList;
    }

    /**
     * 通过医疗服务代码获取参与人员对照
     *
     * @param itemCode       医疗服务代码
     * @param departmentCode 科室代码
     * @return 列表
     */
    @Override
    public Object getItemEmpMap(String itemCode, String departmentCode) {
        List<ItemEmpMap> list = itemEmpMapRepository.getList(itemCode,departmentCode);
        List<EmpCostType> empCostTypes = empCostTypeRepository.getList();
        if (CollectionUtils.isEmpty(empCostTypes)) {
            log.error("未维护人员类别，请先维护人员类别数据");
            throw new CostException("未维护人员类别，请先维护人员类别数据");
        }
        Map<String, String> empCostMap = empCostTypes.stream().collect(Collectors.toMap(EmpCostType::getCostTypeCode, EmpCostType::getCostTypeName, (a, b) -> b));
        for (ItemEmpMap empMap : list) {
            empMap.setEmpTypeCodeName(empCostMap.get(empMap.getEmpTypeCode()));
        }
        return list;
    }

    /**
     * 新增参与人员类别
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void addItemEmpMap(ItemEmpMap request) {
        request.setHospId(UserContext.getHospId());
        request.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        request.setCreateTime(new Date());
        itemEmpMapRepository.save(request);
    }

    /**
     * 编辑参与人员类别
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void editItemEmpMap(ItemEmpMap request) {
        Integer id = request.getId();
        if (id == null) {
            throw new CostException("编辑时主键必填");
        }
        ItemEmpMap item = itemEmpMapRepository.getById(id);
        if (Objects.nonNull(item)) {
            BeanUtil.convertObj(request, item);
            item.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            item.setUpdateTime(new Date());
            itemEmpMapRepository.updateById(item);
        }
    }

    /**
     * 删除参与人员类别
     *
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteItemEmpMap(Integer id) {
        itemEmpMapRepository.deleteItemEmpMap(id);
    }

    /**
     * 获取医疗服务项目与设备对照
     *
     * @param itemCode       医疗服务代码
     * @param departmentCode 科室代码
     * @return 列表
     */
    @Override
    public Object getItemEquipmentMap(String itemCode, String departmentCode) {
        List<ItemEquipmentMap> list = itemEquipmentMapRepository.getList(itemCode,departmentCode);
        List<Equipment> equipmentList = equipmentRepository.getList();
        if (CollectionUtils.isEmpty(equipmentList)) {
            log.error("未维护设备信息，请先设备信息数据");
            throw new CostException("未维护设备信息，请先设备信息数据");
        }
        Map<String, String> equipmentMap = equipmentList.stream().collect(Collectors.toMap(Equipment::getCode, Equipment::getName, (a, b) -> b));
        for (ItemEquipmentMap empMap : list) {
            empMap.setEquipmentCodeName(equipmentMap.get(empMap.getEquipmentCode()));
        }
        return list;
    }

    /**
     * 新增医疗服务项目与设备对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void addItemEquipmentMap(ItemEquipmentMap request) {
        request.setHospId(UserContext.getHospId());
        request.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        request.setCreateTime(new Date());
        itemEquipmentMapRepository.save(request);
    }

    /**
     * 编辑医疗服务项目与设备对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void editItemEquipmentMap(ItemEquipmentMap request) {
        Integer id = request.getId();
        if (id == null) {
            throw new CostException("编辑时主键必填");
        }
        ItemEquipmentMap item = itemEquipmentMapRepository.getById(id);
        if (Objects.nonNull(item)) {
            BeanUtil.convertObj(request, item);
            item.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            item.setUpdateTime(new Date());
            itemEquipmentMapRepository.updateById(item);
        }
    }

    /**
     * 删除医疗服务项目与设备对照
     *
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteItemEquipmentMap(Integer id) {
        itemEquipmentMapRepository.deleteItemEquipmentMap(id);

    }

    /**
     * 获取医疗服务项目与空间对照
     *
     * @param itemCode       医疗服务项目代码
     * @param departmentCode 科室代码
     * @return 列表
     */
    @Override
    public Object getItemSpaceMap(String itemCode, String departmentCode) {
        List<ItemSpaceMap> itemSpaceList = itemSpaceMapRepository.getList(itemCode,departmentCode);
        List<Space> list = spaceRepository.getList();
        if (CollectionUtils.isEmpty(list)) {
            log.error("未维空间成本信息，请先维护空间成本信息数据");
            throw new CostException("未维空间成本信息，请先维护空间成本信息数据");
        }
        Map<String, String> equipmentMap = list.stream().collect(Collectors.toMap(Space::getCode, Space::getName, (a, b) -> b));
        for (ItemSpaceMap map : itemSpaceList) {
            map.setSpaceCodeName(equipmentMap.get(map.getSpaceCode()));
        }
        return itemSpaceList;
    }

    /**
     * 新增医疗服务项目与空间对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void addItemSpaceMap(ItemSpaceMap request) {
        request.setHospId(UserContext.getHospId());
        request.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
        request.setCreateTime(new Date());
        itemSpaceMapRepository.save(request);
    }

    /**
     * 编辑医疗服务项目与空间对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void editItemSpaceMap(ItemSpaceMap request) {
        Integer id = request.getId();
        if (id == null) {
            throw new CostException("编辑时主键必填");
        }
        ItemSpaceMap item = itemSpaceMapRepository.getById(id);
        if (Objects.nonNull(item)) {
            BeanUtil.convertObj(request, item);
            item.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            item.setUpdateTime(new Date());
            itemSpaceMapRepository.updateById(item);
        }
    }

    /**
     * 删除医疗服务项目与空间对照
     *
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteItemSpaceMap(Integer id) {
        itemSpaceMapRepository.deleteItemSpaceMap(id);

    }

    /**
     * 获取不计价药材
     *
     * @param itemCode       医疗服务项目代码
     * @param departmentCode
     * @return 列表
     */
    @Override
    public Object getItemNoValuationDrugMaterialMap(String itemCode, String departmentCode) {
        List<ItemNoValuationDrugMaterialMap> list = itemNoValuationDrugMaterialMapRepository.getList(itemCode,departmentCode);
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        for (ItemNoValuationDrugMaterialMap materialMap : list) {
            Integer type = materialMap.getType();
            if (type.equals(NumberConstant.ONE)) {
                materialMap.setTypeName("药品");
            } else if (type.equals(NumberConstant.TWO)) {
                materialMap.setTypeName("材料");
            }
        }
        return list;
    }

    /**
     * 新增医疗服务项目与不计价药材对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void addItemNoValuationDrugMaterialMap(ItemMapRequest request) {
        String itemCode = request.getItemCode();
        List<ItemMapVo> items = request.getItems();
        if (CollectionUtils.isEmpty(items)) {
            throw new CostException("未传入任何需要保存的数据，无需保存");
        }
        List<ItemNoValuationDrugMaterialMap> list = BeanUtil.convertList(items, ItemNoValuationDrugMaterialMap.class);
        for (ItemNoValuationDrugMaterialMap item : list) {
            item.setItemCode(itemCode);
            item.setDepartmentCode(request.getDepartmentCode());
            item.setCreateTime(new Date());
            item.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            item.setHospId(UserContext.getHospId());
            item.setNum(NumberConstant.ONE);
        }
        itemNoValuationDrugMaterialMapRepository.saveBatch(list);
    }

    /**
     * 编辑医疗服务项目与不计价药材对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void editItemNoValuationDrugMaterialMap(ItemNoValuationDrugMaterialMap request) {
        Integer id = request.getId();
        if (id == null) {
            throw new CostException("编辑时主键必填");

        }
        ItemNoValuationDrugMaterialMap itemMap = itemNoValuationDrugMaterialMapRepository.getById(id);
        if (Objects.nonNull(itemMap)) {
            BeanUtil.convertObj(request, itemMap);
            itemMap.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            itemMap.setUpdateTime(new Date());
            itemNoValuationDrugMaterialMapRepository.updateById(itemMap);
        }
    }

    /**
     * 删除医疗服务项目与不计价药材对照
     *
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteItemNoValuationDrugMaterialMap(Integer id) {
        itemNoValuationDrugMaterialMapRepository.removeByIds(Collections.singleton(id));
    }

    /**
     * 获取医疗服务项目与计价药材对照
     *
     * @param itemCode       医疗服务项目代码
     * @param departmentCode
     * @return 列表
     */
    @Override
    public Object getItemValuationDrugMaterialMap(String itemCode, String departmentCode) {
        List<ItemValuationDrugMaterialMap> list = itemValuationDrugMaterialMapRepository.getList(itemCode,departmentCode);
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        for (ItemValuationDrugMaterialMap materialMap : list) {
            Integer type = materialMap.getType();
            if (type.equals(NumberConstant.ONE)) {
                materialMap.setTypeName("药品");
            } else if (type.equals(NumberConstant.TWO)) {
                materialMap.setTypeName("材料");
            }
        }
        return list;
    }

    /**
     * 新增医疗服务项目与计价药材对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void addItemValuationDrugMaterialMap(ItemMapRequest request) {
        String itemCode = request.getItemCode();
        List<ItemMapVo> items = request.getItems();
        if (CollectionUtils.isEmpty(items)) {
            throw new CostException("未传入任何需要保存的数据，无需保存");
        }
        List<ItemValuationDrugMaterialMap> list = BeanUtil.convertList(items, ItemValuationDrugMaterialMap.class);
        for (ItemValuationDrugMaterialMap item : list) {
            item.setItemCode(itemCode);
            item.setDepartmentCode(request.getDepartmentCode());
            item.setCreateTime(new Date());
            item.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            item.setHospId(UserContext.getHospId());
            item.setNum(NumberConstant.ONE);
        }
        itemValuationDrugMaterialMapRepository.saveBatch(list);
    }

    /**
     * 编辑医疗服务项目与计价药材对照
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void editItemValuationDrugMaterialMap(ItemValuationDrugMaterialMap request) {
        Integer id = request.getId();
        if (id == null) {
            throw new CostException("编辑时主键必填");

        }
        ItemValuationDrugMaterialMap itemMap = itemValuationDrugMaterialMapRepository.getById(id);
        if (Objects.nonNull(itemMap)) {
            BeanUtil.convertObj(request, itemMap);
            itemMap.setUpdateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            itemMap.setUpdateTime(new Date());
            itemValuationDrugMaterialMapRepository.updateById(itemMap);
        }
    }

    /**
     * 删除医疗服务项目与计价药材对照
     *
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteItemValuationDrugMaterialMap(Integer id) {
        itemValuationDrugMaterialMapRepository.removeByIds(Collections.singleton(id));

    }

    /**
     * 批量删除医疗服务项目与不计价药材对照
     *
     * @param ids 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void batchDeleteItemNoValuationDrugMaterialMap(List<Integer> ids) {
        itemNoValuationDrugMaterialMapRepository.removeByIds(ids);
    }

    /**
     * 批量删除医疗服务项目与计价药材对照
     *
     * @param ids 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void batchDeleteItemValuationDrugMaterialMap(List<Integer> ids) {
        itemValuationDrugMaterialMapRepository.removeByIds(ids);

    }

    DrugService drugService;

    MaterialService materialService;

    @Override
    public Object getItemDict(Integer type, String itemCode, String name) {
        List<OrderItemMap> orderItemMaps = new ArrayList<>();
        if (type.equals(NumberConstant.ONE)) {
            //药品
            orderItemMaps = drugService.getItemDict(name);
        } else if (type.equals(NumberConstant.TWO)) {
            //材料
            orderItemMaps = materialService.getItemDict(name);
        }
        //获取已对照的项目
        List<ItemValuationDrugMaterialMap> itemValuation = itemValuationDrugMaterialMapRepository.getByItemCode(itemCode);
        List<ItemNoValuationDrugMaterialMap> itemNoValuation = itemNoValuationDrugMaterialMapRepository.getByItemCode(itemCode);

        if (!CollectionUtils.isEmpty(itemValuation)) {
            List<String> list = itemValuation.stream().map(ItemValuationDrugMaterialMap::getItemCode).collect(Collectors.toList());

            List<OrderItemMap> removeList = orderItemMaps.stream().filter(orderItemMap -> list.contains(orderItemMap.getItemCode())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(removeList)) {
                orderItemMaps.removeAll(removeList);
            }
        }

        if (!CollectionUtils.isEmpty(itemNoValuation)) {
            List<String> list = itemNoValuation.stream().map(ItemNoValuationDrugMaterialMap::getItemCode).collect(Collectors.toList());
            List<OrderItemMap> removeList = orderItemMaps.stream().filter(orderItemMap -> list.contains(orderItemMap.getItemCode())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(removeList)) {
                orderItemMaps.removeAll(removeList);
            }
        }
        List<ItemMapVo> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderItemMaps)) {
            for (OrderItemMap orderItemMap : orderItemMaps) {
                ItemMapVo vo = new ItemMapVo();
                vo.setCode(orderItemMap.getItemCode());
                vo.setName(orderItemMap.getItemName());
                vo.setType(type);
                list.add(vo);
            }
            return list;
        }
        return new ArrayList<ItemMapVo>();
    }

    @Override
    public Object getReferralMatch(String itemCode, String departmentCode) {
        //获取收费项目
        Item item = repository.getOneByCode(itemCode,departmentCode);
        if (Objects.isNull(item)) {
            throw new CostException("未找到代码为【" + itemCode + "】的医疗服务项目");
        }
        //获取标准项目
        List<StandItem> list = standItemRepository.getList();
        if (CollectionUtils.isEmpty(list)) {
            throw new CostException("未找到任何标准项目");
        }
        AutoMatchResponse response = new AutoMatchResponse();
        response.setAllStandItem(list);

        CommonParameterVo parameter = centerService.getParameter(AUTO_MATCH_PERCENT);
        if (Objects.isNull(parameter)) {
            throw new CostException("未找到智能匹配百分比识别区间参数");
        }
        String value = parameter.getValue();
        if (StringUtils.isEmpty(value)) {
            throw new CostException("智能匹配百分比识别区间参数为空");
        }
        Double compare = Double.valueOf(value);
        List<StandItem> returnList = new ArrayList<>();
        DecimalFormat df = new DecimalFormat("0.00%");

//        Double similarity11 = MatchTextComparatorUtil.calculateSimilarity("普通门诊诊查费", "普通门诊诊查费");


        List<StandItem> standItems = BeanUtil.convertList(list, StandItem.class);
        for (StandItem standItem : list) {
            Double similarity = MatchTextComparatorUtil.calculateSimilarity(item.getName(), standItem.getName());
            if (similarity.compareTo(compare) >= 0) {
                standItem.setPercent(similarity);
                standItem.setPercentDisplay(df.format(similarity));
                standItem.setHistoryFlag(NumberConstant.ZERO);
                returnList.add(standItem);
            }
        }
        //所有医疗服务项目匹配
        List<HistoryMatch> historyMatches = historyMatchRepository.list();

        if (!CollectionUtils.isEmpty(historyMatches)) {
            List<HistoryMatch> matchItem = new ArrayList<>();
            for (HistoryMatch match : historyMatches) {
                Double similarity = MatchTextComparatorUtil.calculateSimilarity(item.getName(), match.getName());
                if (similarity.compareTo(compare) >= 0) {
                    match.setPercent(similarity);
                    match.setPercentDisplay(df.format(similarity));
                    match.setHistoryFlag(NumberConstant.ONE);
                    match.setHistoryName(match.getName());
                    matchItem.add(match);
                }
            }
            if (!CollectionUtils.isEmpty(matchItem)) {
                List<HistoryMatch> collect = matchItem.stream().filter(f -> !StringUtils.isEmpty(f.getStandItemCode())).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(collect)) {
                    List<String> standItemCodes = collect.stream().map(HistoryMatch::getStandItemCode).collect(Collectors.toList());
                    Map<String, Double> matchPercent = collect.stream().collect(Collectors.toMap(HistoryMatch::getStandItemCode, HistoryMatch::getPercent, (a, b) -> b));
                    Map<String, String> matchPercentDisplay = collect.stream().collect(Collectors.toMap(HistoryMatch::getStandItemCode, HistoryMatch::getPercentDisplay, (a, b) -> b));
                    Map<String, String> matchHistoryName = collect.stream().collect(Collectors.toMap(HistoryMatch::getStandItemCode, HistoryMatch::getHistoryName, (a, b) -> b));

                    List<StandItem> matchStandList = new ArrayList<>();
                    for (StandItem standItem : standItems) {
                        if (standItemCodes.contains(standItem.getCode())) {
                            standItem.setPercent(matchPercent.get(standItem.getCode()));
                            standItem.setPercentDisplay(matchPercentDisplay.get(standItem.getCode()));
                            standItem.setHistoryFlag(NumberConstant.ONE);
                            standItem.setHistoryName(matchHistoryName.get(standItem.getCode()));
                            matchStandList.add(standItem);
                        }
                    }
                    if (!CollectionUtils.isEmpty(matchStandList)) {
                        returnList.addAll(matchStandList);
                        returnList.sort(Comparator.comparing(StandItem::getPercent).reversed());
                        List<StandItem> collect1 = returnList.stream().filter(distinctByKey(StandItem::getCode)).collect(Collectors.toList());
                        returnList.clear();
                        returnList.addAll(collect1);
                    }
                }
            }
        }
        if (!CollectionUtils.isEmpty(returnList)) {
            returnList.sort(Comparator.comparing(StandItem::getPercent).reversed());
            if (returnList.size() > 10) {
                List<StandItem> matchList = returnList.subList(0, 10);
                response.setMatchStandItem(matchList);
            } else {
                response.setMatchStandItem(returnList);
            }
        }
        return response;
    }

    /**
     * 智能对照-获取对照数据
     *
     * @return 对照数据计数
     */
    @Override
    public Object getMatchCount() {
        List<Item> list = repository.getList();
        if (CollectionUtils.isEmpty(list)) {
            throw new CostException("未找到医疗服务项目");
        }
        long trueMatch = list.stream().filter(f -> !StringUtils.isEmpty(f.getStandItemCode())).count();
        long falseMatch = list.stream().filter(f -> StringUtils.isEmpty(f.getStandItemCode())).count();
        MatchCountResponse response = new MatchCountResponse();
        response.setAllCount(list.size());
        response.setTrueMatch(trueMatch);
        response.setFalseMatch(falseMatch);
        return response;
    }

    /**
     * 智能对照-获取收费项目信息
     *
     * @param itemCode       收费项目代码
     * @param departmentCode 科室代码
     * @return 收费项目
     */
    @Override
    public Object getSingleItem(String itemCode, String departmentCode) {
        Item item = repository.getOneByCode(itemCode,departmentCode);
        if (Objects.isNull(item)) {
            throw new CostException("未找到代码为【" + itemCode + "】的医疗服务项目");
        }
        item.setMatch(!StringUtils.isEmpty(item.getStandItemCode()));
        return item;
    }

    /**
     * 智能对照-获取收费项目信息列表
     *
     * @return 收费项目列表
     */
    @Override
    public Object getSingleItemList() {
        List<Item> list = repository.getList();
        if (CollectionUtils.isEmpty(list)) {
            throw new CostException("未找到医疗服务项目");
        }
        if (!CollectionUtils.isEmpty(list)) {
            list.forEach(item -> item.setMatch(!StringUtils.isEmpty(item.getStandItemCode())));
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void matchItem(String itemCode, String standItemCode, Integer type, String departmentCode) {
        Item item = repository.getOneByCode(itemCode,departmentCode);
        StandItem standItem = standItemRepository.getOneByCode(standItemCode);
        if (Objects.nonNull(standItem)) {
            item.setStandItemCode(standItem.getCode());
            item.setStandItemName(standItem.getName());
            item.setKcCode(standItem.getKcClassCode());
        }
        repository.updateById(item);
        //当前院区同一项目是否已匹配过 已匹配过作废
        historyMatchRepository.removeByItemCode(itemCode);

        List<HistoryMatch> byFilter = historyMatchRepository.getByFilter(item.getName(), standItem.getCode(), standItem.getName());
        if (CollectionUtils.isEmpty(byFilter)) {
            HistoryMatch historyMatch = new HistoryMatch();
            historyMatch.setHospId(UserContext.getCurrentLoginHospId());
            historyMatch.setMatchType(MatchTypeEnum.ITEM_MATCH.getType());
            historyMatch.setCode(item.getCode());
            historyMatch.setName(item.getName());
            historyMatch.setKcCode(standItem.getKcClassCode());
            historyMatch.setStandItemCode(standItem.getCode());
            historyMatch.setStandItemName(standItem.getName());
            historyMatch.setType(type);
            historyMatchRepository.save(historyMatch);
        }
    }

    static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
}
