package com.zt.plat.module.qms.business.bus.liteflow.sample.taskassign;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import com.zt.plat.framework.security.core.LoginUser;
import com.zt.plat.module.qms.business.bus.dal.dataobject.BusinessAssayTaskDO;
import com.zt.plat.module.qms.business.bus.dal.dataobject.BusinessAssayTaskDataDO;
import com.zt.plat.module.qms.business.bus.dal.dataobject.BusinessAssayTaskDetailDO;
import com.zt.plat.module.qms.business.bus.dal.dataobject.BusinessSubSampleDO;
import com.zt.plat.module.qms.business.bus.dal.mapper.BusinessAssayTaskDataMapper;
import com.zt.plat.module.qms.business.bus.dal.mapper.BusinessAssayTaskMapper;
import com.zt.plat.module.qms.business.bus.dal.mapper.BusinessSubSampleMapper;
import com.zt.plat.module.qms.business.bus.liteflow.param.AssignAssayUser;
import com.zt.plat.module.qms.business.bus.liteflow.slot.SampleTaskAssignContext;
import com.zt.plat.module.qms.business.bus.liteflow.slot.SampleTaskAssignTypeEnum;
import com.zt.plat.module.qms.business.config.dal.dataobject.ConfigAssayMethodDO;
import com.zt.plat.module.qms.business.config.dal.dataobject.ConfigReportTemplateDO;
import com.zt.plat.module.qms.business.config.dal.mapper.ConfigAssayMethodMapper;
import com.zt.plat.module.qms.business.config.dal.mapper.ConfigReportTemplateMapper;
import com.zt.plat.module.qms.common.dic.dal.dataobject.DictionaryBusinessDO;
import com.zt.plat.module.qms.common.dic.dal.mapper.DictionaryBusinessMapper;
import com.zt.plat.module.qms.core.code.SequenceUtil;
import com.zt.plat.module.qms.enums.QmsCommonConstant;

import jakarta.annotation.Resource;


@LiteflowComponent(id = "sampleTaskAssignManualTypeCmp", name = "手动分配(按分析方法类型)")
public class SampleTaskAssignManualTypeCmp extends NodeComponent {

	@Resource
	private SequenceUtil sequenceUtil;
	
	@Resource
	private DictionaryBusinessMapper dictionaryBusinessMapper;
	
	@Resource
	private ConfigAssayMethodMapper configAssayMethodMapper;
	
	@Resource
	private ConfigReportTemplateMapper configReportTemplateMapper;
	
	@Resource
	private BusinessAssayTaskDataMapper businessAssayTaskDataMapper;
	
	@Resource
	private BusinessAssayTaskMapper businessAssayTaskMapper;
	
	@Resource
	private BusinessSubSampleMapper businessSubSampleMapper;

	@Override
	public void process() throws Exception {
		SampleTaskAssignContext sampleTaskAssignContext = this.getContextBean(SampleTaskAssignContext.class);
		String loginRealname = sampleTaskAssignContext.getLoginRealname();
		LoginUser loginUser = sampleTaskAssignContext.getLoginUser();
		LocalDateTime currentDateTime = sampleTaskAssignContext.getCurrentDateTime();
//		AssignAssayUser assignAssayUser = sampleTaskAssignContext.getAssignAssayUser();
		List<AssignAssayUser> assignAssayUserList = sampleTaskAssignContext.getAssignAssayUserList();
		int assignAssayUserCount = assignAssayUserList.size();
		List<Long> assayTaskDataIdList = sampleTaskAssignContext.getAssayTaskDataIdList();
		List<BusinessAssayTaskDataDO> businessAssayTaskDataList = businessAssayTaskDataMapper.selectByIds(assayTaskDataIdList);
		List<Long> businessSubSampleIdList = businessAssayTaskDataList.stream().map(m -> m.getBusinessSubSampleId()).distinct().collect(Collectors.toList());
		List<Long> configAssayMethodIdList = businessAssayTaskDataList.stream().map(m -> m.getConfigAssayMethodId()).distinct().collect(Collectors.toList());
		List<ConfigAssayMethodDO> configAssayMethodList = configAssayMethodMapper.selectByIds(configAssayMethodIdList);
		sampleTaskAssignContext.setConfigAssayMethodList(configAssayMethodList);
		
		//查询子样
		List<BusinessSubSampleDO> businessSubSampleList = businessSubSampleMapper.selectByIds(businessSubSampleIdList);
		sampleTaskAssignContext.setBusinessSubSampleList(businessSubSampleList);
		
		//保存任务分配单
		List<BusinessAssayTaskDO> saveBusinessAssayTaskList = new ArrayList<>();
		//更新任务分配单
		List<BusinessAssayTaskDO> updateBusinessAssayTaskList = new ArrayList<>();
		//任务分配单明细
		List<BusinessAssayTaskDetailDO> businessAssayTaskDetailList = new ArrayList<>();
		
		// 用于缓存已处理的任务单，避免同一用户在同一业务类型下重复查询数据库
	    // Key: userId + dictionaryBusinessId, Value: BusinessAssayTaskDO
	    Map<String, BusinessAssayTaskDO> existingTaskCache = new HashMap<>();
		
		//按方法类型分组
		Map<Long, List<ConfigAssayMethodDO>> groupConfigAssayMethodListMap = configAssayMethodList.stream().collect(Collectors.groupingBy(ConfigAssayMethodDO::getDictionaryBusinessId));
		//Map<Long, List<BusinessAssayTaskDataDO>> groupBusinessAssayTaskDataListMap = businessAssayTaskDataList.stream().collect(Collectors.groupingBy(BusinessAssayTaskDataDO::get));
		for (Map.Entry<Long, List<ConfigAssayMethodDO>> entry : groupConfigAssayMethodListMap.entrySet()) {
			long dictionaryBusinessId = entry.getKey();
			List<ConfigAssayMethodDO> currConfigAssayMethodList = entry.getValue();
			List<Long> currConfigAssayMethodIdList = currConfigAssayMethodList.stream().map(m -> m.getId()).collect(Collectors.toList());
			ConfigAssayMethodDO configAssayMethod = currConfigAssayMethodList.get(0);
//			ConfigAssayMethodDO configAssayMethod = sampleTaskAssignContext.getConfigAssayMethodById(key);
			DictionaryBusinessDO dictionaryBusinessDO = dictionaryBusinessMapper.selectById(dictionaryBusinessId);
			//查询报表模板
			ConfigReportTemplateDO configReportTemplate = configReportTemplateMapper.selectLatestConfigReportTemplateByKey(configAssayMethod.getConfigReportTemplateKey());


	        // 筛选出当前业务类型下的所有待分配数据
	        List<BusinessAssayTaskDataDO> valList = businessAssayTaskDataList.stream()
	                .filter(f -> currConfigAssayMethodIdList.contains(f.getConfigAssayMethodId()))
	                .collect(Collectors.toList());

	        if (valList.isEmpty()) {
	            continue;
	        }

	        // 【核心修改】轮询分配逻辑
	        // 不再是为整个组创建一个任务单，而是根据数据量，将数据平均分给 list 中的用户
	        for (int i = 0; i < valList.size(); i++) {
	            BusinessAssayTaskDataDO val = valList.get(i);
	            
	            // 1. 确定当前数据分配给哪个用户 (轮询)
	            AssignAssayUser currentUser = assignAssayUserList.get(i % assignAssayUserCount);
	            String currentOperatorName = currentUser.getRealName();
	            Long currentOperatorId = currentUser.getUserId();

	            // 2. 查找或创建该用户在此业务类型下的任务单
	            // 缓存Key：用户ID_业务ID
	            String cacheKey = currentOperatorId + "_" + dictionaryBusinessId;
	            BusinessAssayTaskDO businessAssayTaskDO = existingTaskCache.get(cacheKey);

	            if (businessAssayTaskDO == null) {
	                // 缓存没命中，去数据库查该用户是否有进行中的任务
	                businessAssayTaskDO = businessAssayTaskMapper.selectAssignInProgressByAssayUserAndAssignUser(
	                        dictionaryBusinessId, currentOperatorName, loginRealname);
	                
	                if (businessAssayTaskDO == null) {
	                    // 没有进行中任务，新建
	                    String taskNo = sequenceUtil.genCode(configAssayMethod.getCodeRule());
	                    businessAssayTaskDO = new BusinessAssayTaskDO();
	                    businessAssayTaskDO.setId(IdWorker.getId());
	                    businessAssayTaskDO.setTaskNo(taskNo);
	                    businessAssayTaskDO.setTaskName(dictionaryBusinessDO.getName());
	                    
	                    // 设置当前轮询到的操作员
	                    businessAssayTaskDO.setAssayOperator(currentOperatorName);
	                    businessAssayTaskDO.setAssayOperatorId(currentOperatorId);
	                    
	                    businessAssayTaskDO.setConfigAssayMethodId(configAssayMethod.getId());
	                    businessAssayTaskDO.setDictionaryBusinessId(dictionaryBusinessId);
	                    businessAssayTaskDO.setDictionaryBusinessKey(configAssayMethod.getDictionaryBusinessKey());
	                    businessAssayTaskDO.setTaskSourceType(QmsCommonConstant.TASK_ASSIGN);
	                    businessAssayTaskDO.setConfigReportTemplateId(configReportTemplate.getId());
	                    businessAssayTaskDO.setConfigReportTemplateKey(configReportTemplate.getKey());
	                    businessAssayTaskDO.setIsIngredients(configAssayMethod.getIsIngredients());
	                    businessAssayTaskDO.setIngredientsStatus("initial");

	                    businessAssayTaskDO.setTaskAssignOperator(loginRealname);
	                    businessAssayTaskDO.setTaskAssignOperatorId(loginUser.getId());
	                    businessAssayTaskDO.setTaskAssignTime(currentDateTime);
	                    businessAssayTaskDO.setTaskAssignStatus(QmsCommonConstant.IN_PROGRESS);
	                    businessAssayTaskDO.setTaskAssayStatus(QmsCommonConstant.NOT_START);
	                    businessAssayTaskDO.setFinishStatus(QmsCommonConstant.NOT_START);
	                    businessAssayTaskDO.setFlowStatus(QmsCommonConstant.NOT_START);

	                    saveBusinessAssayTaskList.add(businessAssayTaskDO);
	                } else {
	                    updateBusinessAssayTaskList.add(businessAssayTaskDO);
	                }
	                // 放入缓存，后续同用户同业务类型的直接复用
	                existingTaskCache.put(cacheKey, businessAssayTaskDO);
	            }

	            // 3. 更新原始数据状态
	            val.setIsAssignTasked(QmsCommonConstant.YES);
	            val.setAssignTaskTime(currentDateTime);
	            // 注意：这里也要更新为当前轮询到的操作员，而不是固定的某个人
	            val.setAssayOperator(currentOperatorName);
	            val.setAssayOperatorId(currentOperatorId);
	            val.setBusinessAssayTaskId(businessAssayTaskDO.getId());

	            // 4. 构建任务明细
	            BusinessSubSampleDO businessSubSampleDO = sampleTaskAssignContext.getBusinessSubSampleById(val.getBusinessSubSampleId());
	            
	            BusinessAssayTaskDetailDO businessAssayTaskDetailDO = new BusinessAssayTaskDetailDO();
	            businessAssayTaskDetailDO.setBusinessAssayTaskDataId(val.getId());
	            businessAssayTaskDetailDO.setBusinessAssayTaskId(businessAssayTaskDO.getId());
	            businessAssayTaskDetailDO.setTaskNo(businessAssayTaskDO.getTaskNo());
	            businessAssayTaskDetailDO.setSampleId(val.getBusinessSubSampleId());
	            businessAssayTaskDetailDO.setSampleCode(businessSubSampleDO.getSampleAssayCode());
	            businessAssayTaskDetailDO.setSampleName(businessSubSampleDO.getSampleName());
	            businessAssayTaskDetailDO.setDataSourceType(QmsCommonConstant.NORMAL);
	            // 如果需要全局排序，这里的 sortNo 可能需要重新计算，如果是按任务单内部排序，保持自增即可
	            // 由于现在拆分了任务单，每个任务单内部的 sortNo 最好单独维护，这里简单处理为累加（实际可能需按任务单分组后重排）
	            // 建议：如果在同一个任务单内，sortNo 应该是连续的。由于我们是循环插入，可能需要后期整理，或者在这里维护一个 Map<TaskId, SortNo>
	            // 为了简化，这里暂时保持原有逻辑，实际生产中建议在循环结束后按 taskId 分组重新设置 sortNo
	            
	            businessAssayTaskDetailList.add(businessAssayTaskDetailDO);
	        }
	        			
		}
	    // 【可选优化】重新整理明细的排序号 (SortNo)，确保每个任务单内的明细是 1, 2, 3...
	    // 因为上面的循环是交叉写入的，可能导致同一个 taskId 的 sortNo 不连续 (如 1, 1, 2, 2...) 如果多个用户交替
	    // 实际上上面的逻辑中，同一个 taskId 是由同一个用户产生的，但因为是交叉循环，可能插入顺序是交错的。
	    // 最稳妥的方式是按 taskId 分组重排
	    Map<Long, Integer> sortCounterMap = new HashMap<>();
	    for (BusinessAssayTaskDetailDO detail : businessAssayTaskDetailList) {
	        Long taskId = detail.getBusinessAssayTaskId();
	        int currentSort = sortCounterMap.getOrDefault(taskId, 0) + 1;
	        detail.setSortNo(currentSort);
	        sortCounterMap.put(taskId, currentSort);
	    }

		sampleTaskAssignContext.setSaveBusinessAssayTaskList(saveBusinessAssayTaskList);
		sampleTaskAssignContext.setUpdateBusinessAssayTaskList(updateBusinessAssayTaskList);
		sampleTaskAssignContext.setBusinessAssayTaskDataList(businessAssayTaskDataList);
		sampleTaskAssignContext.setBusinessAssayTaskDetailList(businessAssayTaskDetailList);
		
	}

	@Override
	public boolean isAccess() {
		SampleTaskAssignContext sampleTaskAssignContext = this.getContextBean(SampleTaskAssignContext.class);
		return sampleTaskAssignContext.getSampleTaskAssignType().equals(SampleTaskAssignTypeEnum.MANUAL_TYPE);
	}

}
