package com.sw.mes.yb.production.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import com.sw.mes.base.global.GlobalSwitch;
import com.sw.mes.base.global.GlobalSwitchNamespace;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.NumberUtil;
import com.sw.mes.crucible.entity.CrucibleFixedCasting;
import com.sw.mes.crucible.service.CrucibleFixedCastingService;
import com.sw.mes.mqtt.service.NotificationService;
import com.sw.mes.production.dto.DecompositionSchemeParam;
import com.sw.mes.production.dto.FormulaSchemeData;
import com.sw.mes.production.entity.FormulaProductScheme;
import com.sw.mes.production.entity.FormulaProductSchemeDetail;
import com.sw.mes.production.entity.FormulaWeightScheme;
import com.sw.mes.production.service.*;
import com.sw.mes.yb.mcs.service.YbMesToMcsService;
import com.sw.mes.yb.pad.dto.DrawLineDetailDto;
import com.sw.mes.yb.plan.entity.ProductionSchedule;
import com.sw.mes.yb.production.dto.AgainTaskPrepare.AgainTaskPrepareDto;
import com.sw.mes.yb.production.entity.*;
import com.sw.mes.yb.production.entity.AgainTaskPrepare.AgainTaskPrepare;
import com.sw.mes.yb.production.service.*;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sw.mes.core.constant.ScheduleConstants;
import com.sw.mes.base.system.entity.DictionaryItem;
import com.sw.mes.base.system.service.DictionaryItemService;
import com.sw.mes.core.utils.BeanUtil;
import com.sw.mes.mmcs.service.MMcsInterfaceService;
import com.sw.mes.quartz.entity.SysJob;
import com.sw.mes.quartz.service.SysJobService;
import com.sw.mes.quartz.util.CronUtils;
import com.sw.mes.yb.production.dto.AgainTask.AgainTaskDto;
import com.sw.mes.yb.production.dto.LoadingTask.LoadingTaskDto;
import com.sw.mes.yb.production.notification.AgainTaskMessage;
import org.springframework.util.ObjectUtils;

/**
 * @author 李儒
 */
@Service
@Transactional
public class EAPDockingServiceImpl implements EAPDockingService {

	@Autowired
	ModelMapper modelMapper;

	@Autowired
	private DictionaryItemService dictionaryItemService;

	@Autowired
	private ProductionCircleRecipeService productionCircleRecipeService;
	@Autowired
	private ProductionCircleWeightService productionCircleWeightService;

	@Autowired
	private LoadingTaskService loadingTaskService;
	@Autowired
	private AgainTaskService againTaskService;
	@Autowired
	private SysJobService sysJobService;
//	@Autowired
//	private TransportInspectTaskService transportInspectTaskService;
	@Autowired
	private NotificationService notificationService;

	@Autowired
	private MMcsInterfaceService mMcsInterfaceService;

	@Autowired
	private CrucibleFixedCastingService crucibleFixedCastingService;    // 热场尺寸

	@Autowired
	private FormulaProductSchemeService formulaProductSchemeService;	// 拆桶方案

	@Autowired
	private FormulaProductSchemeDetailService productSchemeDetailService;  // 方案明细

	@Autowired
	private FormulaWeightSchemeService formulaWeightSchemeService;		// 重量方案

	@Autowired
	private FormulaProductSchemeWeightDetailService productSchemeWeightDetailService; // 方案明细

	@Autowired
	private AgainTaskPrepareService againTaskPrepareService;

	@Autowired
	private FormulaSchemeOutService formulaSchemeOutService;

	@Autowired
	private ProductionFurnaceMaterialSplitService splitService;

	@Autowired
	private YbMesToMcsService mesToMcsService;


	/**装料信号必填项验证**/
	private static Map<String, String> requiredMapping = new HashMap<String, String>();
	/**复投信号必填项验证**/
	private static Map<String, String> againTaskRequiredMapping = new HashMap<String, String>();
	/**送验信号必填项验证**/
	private static Map<String, String> transportInspectTaskMapping = new HashMap<String, String>();



	static {
		//=========================装料必填项验证 ===============================
		requiredMapping.put("equipmentCode", "请设置设备号");
		requiredMapping.put("lotNo", "请设置炉次号");
		requiredMapping.put("series", "请设置所属系列");
		requiredMapping.put("area", "请设置所属模块");
		requiredMapping.put("furnaceType", "请设置炉台类型【0:默认；0-量产;1-在建;2-研发;】");
		requiredMapping.put("sapNo", "请设置SAP订单号");
		requiredMapping.put("productCode", "请设置料号");
//		requiredMapping.put("productGrade", "请设置产品等级");
		requiredMapping.put("specs", "请设置规格");
		requiredMapping.put("dopant", "请设置掺杂剂");
//		requiredMapping.put("productType", "请设置产品类别");


		//=========================复投必填项验证 ===============================
		againTaskRequiredMapping.put("equipmentCode", "请设置设备号");
		againTaskRequiredMapping.put("lotNo", "请设置炉次号");
		againTaskRequiredMapping.put("series", "请设置所属系列");
		againTaskRequiredMapping.put("area", "请设置所属模块");
		againTaskRequiredMapping.put("rawType", "请设置叫料类型【0:默认;1-初始复投;2-取段复投;】");
		againTaskRequiredMapping.put("furnaceType", "请设置炉台类型【0:默认；0-量产;1-在建;2-研发;】");
		againTaskRequiredMapping.put("sapNo", "请设置SAP订单号");
		againTaskRequiredMapping.put("productCode", "请设置料号");
//		againTaskRequiredMapping.put("productGrade", "请设置产品等级");
		againTaskRequiredMapping.put("specs", "请设置规格");
		againTaskRequiredMapping.put("dopant", "请设置掺杂剂");
//		againTaskRequiredMapping.put("productType", "请设置产品类别");


		//=========================复投必填项验证 ===============================
		transportInspectTaskMapping.put("equipmentCode", "请设置设备号");
		transportInspectTaskMapping.put("lotNo", "请设置炉次号");
		transportInspectTaskMapping.put("series", "请设置所属系列");
		transportInspectTaskMapping.put("area", "请设置所属模块");
		transportInspectTaskMapping.put("furnaceType", "请设置炉台类型【0:默认；0-量产;1-在建;2-研发;】");
		transportInspectTaskMapping.put("sapNo", "请设置SAP订单号");
		transportInspectTaskMapping.put("productCode", "请设置料号");
//		transportInspectTaskMapping.put("productGrade", "请设置产品等级");
		transportInspectTaskMapping.put("specs", "请设置规格");
		transportInspectTaskMapping.put("dopant", "请设置掺杂剂");
//		transportInspectTaskMapping.put("productType", "请设置产品类别");
	}

	@Override
	public void zlTaskCreate(LoadingTaskDto taskDto) throws Exception {
		BeanUtil.requiredValidate(taskDto, requiredMapping);
		taskDto.setRawType(0);

		Date currentDate = new Date();
		taskDto.setGmtCreate(currentDate);

		int ettime = getDicMinuteTime("FeedingTask","装料时间",900);

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(currentDate);
		calendar.add(Calendar.MINUTE, ettime);
		taskDto.setEtTime(calendar.getTime());

		// 获取热场坩埚尺寸
		CrucibleFixedCasting fixedCasting = crucibleFixedCastingService.findByEquipment(taskDto.getEquipmentCode());
		if (fixedCasting != null){
			taskDto.setDimensionId(fixedCasting.getId());
			taskDto.setDimension(fixedCasting.getDimension());
		}

		// 设置配方初始装料
		FormulaProductScheme productScheme = formulaProductSchemeService.findByEquipmentCodeAndProductModeCode(
				taskDto.getEquipmentCode(), taskDto.getProductCode());
		if (productScheme == null) throw new RuntimeException("未查询到对应的产品配方方案");
		FormulaProductSchemeDetail schemeDetail = productSchemeDetailService.findByFpsIdAndAgainNum(productScheme.getId(), 0);
		if (ObjectUtils.isEmpty(schemeDetail) && ObjectUtils.isEmpty(productScheme.getInitialFormulaId())){
			throw new RuntimeException("未查询到对应的配方方案");
		}
		FormulaWeightScheme weightScheme = formulaWeightSchemeService.get(schemeDetail.getWeightSchemeId());
		if (weightScheme == null) throw new RuntimeException("未查询到对应的重量方案");

		// 设置初装重量
		taskDto.setWeight(weightScheme.getInitialWeight().setScale(0, RoundingMode.UP));

		// 设置默认信息
		taskDto.setUserName("EAP");
		taskDto.setOperationTime(new Date());

		int delayedTime = getDicMinuteTime("DelayTime","初始装料延迟",0);

		LoadingTask model = fromDto(taskDto);
		if(delayedTime<=0) {
			model.setRawStatus(LoadingTaskDto.rawStatus_0);
			model.setDelayedStartTime(currentDate);
			loadingTaskService.saveOrUpdate(model);
		}else {
			model.setRawStatus(LoadingTaskDto.rawStatus_6);
			calendar.setTime(currentDate);
			calendar.add(Calendar.MINUTE, delayedTime);
			Date delayDate = calendar.getTime();
			model.setDelayedStartTime(delayDate);
			loadingTaskService.saveOrUpdate(model);

			String cronExpression = CronUtils.getCronExpression(delayDate);

			SysJob job = new SysJob();
			job.setJobName("zlTask:"+model.getLotNo() + "-" + model.getId());
			job.setJobGroup("装料");
			job.setInvokeTarget("delayStartTask.zlTask('"+model.getLotNo()+"',"+model.getId()+"L)");
			job.setCronExpression(cronExpression);
			job.setExpireTime(delayDate);
			job.setCreateBy("EAP");
			job.setMisfirePolicy(ScheduleConstants.MISFIRE_DEFAULT);
			job.setConcurrent("0");
			job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
			sysJobService.startJob(job);
		}

		// 获取桶分解方案
		DecompositionSchemeParam decompositionSchemeParam = new DecompositionSchemeParam();
		decompositionSchemeParam.setEquipmentCode(model.getEquipmentCode());
		decompositionSchemeParam.setProductModeCode(model.getProductCode());
		decompositionSchemeParam.setWeight(null);
		decompositionSchemeParam.setType(1);
		decompositionSchemeParam.setRepeatTimes(0);
		decompositionSchemeParam.setIsFillEnd(0);
		FormulaSchemeData formulaSchemeData = formulaSchemeOutService.decompositionScheme(decompositionSchemeParam);
		if (formulaSchemeData == null) {
			throw new RuntimeException("未获取到桶分解数据！");
		}

		// 保存桶分解数据
		List<ProductionFurnaceMaterialSplit> splitList = new ArrayList<>();
		for (FormulaSchemeData.FormulaSchemeDataDetail schemeData : formulaSchemeData.getDetail()) {
			List<FormulaSchemeData.LoadingDetail> detailList = schemeData.getLoadingDetails();
			for (FormulaSchemeData.LoadingDetail detail : detailList) {
				ProductionFurnaceMaterialSplit split = new ProductionFurnaceMaterialSplit();
				split.setEquipmentCode(model.getEquipmentCode());
				split.setLotNo(model.getLotNo());
				split.setRawType(0);
				split.setAgainNum(0);
				split.setProductCode(model.getProductCode());
				split.setTaskId(model.getId());
				split.setSplitInfo(formulaSchemeData, schemeData, detail);
				splitList.add(split);
			}
		}

		// 更新桶分解记录数据
		splitService.deleteByTaskIdAndAgainNum(model.getId(), 0);
		splitService.saveAll(splitList);

		// 配料任务关联配方方案和重量方案
		model.setRecipeId(formulaSchemeData.getSchemeId());
		model.setWeigthId(formulaSchemeData.getWeightSchemeId());
		loadingTaskService.saveOrUpdate(model);

		if (GlobalSwitch.enable(GlobalSwitchNamespace.NAMESPACE_AUTOMATION, "CanningMaterial", false)
			&& delayedTime <= 0) {
			//下发生产任务接口 装罐料下发
			mesToMcsService.issueMoInterface(model);
		}
	}

	@Override
	public void ftTaskCreate(AgainTaskDto task) throws Exception {
		BeanUtil.requiredValidate(task, againTaskRequiredMapping);

		Date currentDate = new Date();
		task.setGmtCreate(currentDate);


		if(task.getRawType() == 1) {//初始复投
			Integer ettime = getDicMinuteTime("FeedingTask","初始复投时间",120);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(currentDate);
			calendar.add(Calendar.MINUTE, ettime);
			task.setEtTime(calendar.getTime());

			// 设置默认信息
			task.setUserName("EAP");

			int delayedTime = getDicMinuteTime("DelayTime","初始复投延迟",0);

			if(delayedTime<=0) {
				task.setRawStatus(LoadingTaskDto.rawStatus_0);
				task.setDelayedStartTime(currentDate);
				AgainTask model = fromDto(task);
				againTaskService.saveOrUpdate(model);

//				//下发生产任务接口
//	    		mMcsInterfaceService.issueMoInterface(model);

				//发送MQTT通知
				AgainTaskMessage message = new AgainTaskMessage();
				message.setArea(model.getArea());
				message.setEquipmentCode(model.getEquipmentCode());
				message.setId(model.getId());
				message.setLotNo(model.getLotNo());
				message.setSeries(model.getSeries());
				notificationService.sendNotification(message);

			}else {
				task.setRawStatus(LoadingTaskDto.rawStatus_6);
				//设置延时时间
				calendar.setTime(currentDate);
				calendar.add(Calendar.MINUTE, delayedTime);
				Date delayDate = calendar.getTime();
				task.setDelayedStartTime(delayDate);

				AgainTask model = fromDto(task);
				againTaskService.saveOrUpdate(model);

				//下发生产任务接口
	    		//mMcsInterfaceService.issueMoInterface(model);

				String cronExpression = CronUtils.getCronExpression(delayDate);

				SysJob job = new SysJob();
				job.setJobName("ftTask:"+task.getLotNo() +"-"+model.getId());
				job.setJobGroup("装料");
				job.setInvokeTarget("delayStartTask.ftTask('"+model.getLotNo()+"',"+model.getId()+"L)");
				job.setCronExpression(cronExpression);
				job.setExpireTime(delayDate);
				job.setCreateBy("EAP");
				job.setMisfirePolicy(ScheduleConstants.MISFIRE_DEFAULT);
				job.setConcurrent("0");
				job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
				sysJobService.startJob(job);
			}


		}else if(task.getRawType() == 2){//取段复投
			Integer ettime = getDicMinuteTime("FeedingTask","取段复投时间",0);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(currentDate);
			calendar.add(Calendar.MINUTE, ettime);
			task.setEtTime(calendar.getTime());
			task.setRawStatus(LoadingTaskDto.rawStatus_0);

			// 改成桶桶分解的时候关联
			/*ProductionCircleRecipe circleRecipe = productionCircleRecipeService.getByProductCode(task.getProductCode());
			task.setRecipeId(circleRecipe == null ? null : circleRecipe.getId());
			ProductionCircleWeight circleWeight = productionCircleWeightService.getByProductCode(task.getProductCode());
			task.setWeigthId(circleWeight == null ? null : circleWeight.getId());*/

			// 设置默认信息
			task.setUserName("EAP");
//			task.setAgainTime(new Date());


			int delayedTime = getDicMinuteTime("DelayTime","取段复投延迟",0);

			if(delayedTime<=0) {
				task.setRawStatus(LoadingTaskDto.rawStatus_0);
				task.setDelayedStartTime(currentDate);
				AgainTask model = fromDto(task);
				againTaskService.saveOrUpdate(model);

				//下发生产任务接口
	    		//mMcsInterfaceService.issueMoInterface(model);


				//发送MQTT通知
				AgainTaskMessage message = new AgainTaskMessage();
				message.setArea(model.getArea());
				message.setEquipmentCode(model.getEquipmentCode());
				message.setId(model.getId());
				message.setLotNo(model.getLotNo());
				message.setSeries(model.getSeries());
				notificationService.sendNotification(message);

			}else {
				task.setRawStatus(LoadingTaskDto.rawStatus_6);

				calendar.setTime(currentDate);
				calendar.add(Calendar.MINUTE, delayedTime);
				Date delayDate = calendar.getTime();
				task.setDelayedStartTime(delayDate);

				AgainTask model = fromDto(task);
				againTaskService.saveOrUpdate(model);

				//下发生产任务接口
	    		//mMcsInterfaceService.issueMoInterface(model);

				String cronExpression = CronUtils.getCronExpression(delayDate);

				SysJob job = new SysJob();
				job.setJobName("ftTask:"+task.getLotNo() +"-"+model.getId());
				job.setJobGroup("装料");
				job.setInvokeTarget("delayStartTask.ftTask('"+model.getLotNo()+"',"+model.getId()+"L)");
				job.setCronExpression(cronExpression);
				job.setExpireTime(delayDate);
				job.setCreateBy("EAP");
				job.setMisfirePolicy(ScheduleConstants.MISFIRE_DEFAULT);
				job.setConcurrent("0");
				job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
				sysJobService.startJob(job);
			}

		}else {
			throw new RuntimeException("叫料类型传入异常【1-初始复投;2-取段复投;】");
		}
	}

	private void saveFormulaScheme(){

	}

//	@Override
//	public void syTaskCreate(TransportInspectTaskDto task) throws Exception{
//		BeanUtil.requiredValidate(task, transportInspectTaskMapping);
//
//		if(task.getLength().floatValue()>=1500) {
//			task.setCreateTime(new Date());
//			task.setSendTask(true);
//			task.setCrystalStatus(TransportInspectTaskDto.crystalStatus_0);
//			TransportInspectTask model = fromDto(task);
//			transportInspectTaskService.saveOrUpdate(model);
//
//			//发送MQTT通知
//			SongYanMessage message = new SongYanMessage();
//			message.setArea(model.getArea());
//			message.setEquipmentCode(model.getEquipmentCode());
//			message.setId(model.getId());
//			message.setLotNo(model.getLotNo());
//			message.setSeries(model.getSeries());
//			notificationService.sendNotification(message);
//		}else {
//			task.setCreateTime(new Date());
//			task.setSendTask(false);
//			task.setCrystalStatus(TransportInspectTaskDto.crystalStatus_0);
//			TransportInspectTask model = fromDto(task);
//			transportInspectTaskService.saveOrUpdate(model);
//		}
//	}



	private Integer getDicMinuteTime(String themeValue,String name , int defValue) {
		int time = 0;
		try {
			//设置预计初始复投时间
			DictionaryItem dic = dictionaryItemService.findByThemeValueAndNameAndEnable(themeValue, name, true);
			if(dic!=null) {
				time = Integer.valueOf(dic.getValue());
			}else {
				time = defValue;
			}
		}catch (Exception e) {
			time = defValue;
		}
		return time;
	}


	private LoadingTask fromDto(LoadingTaskDto dto) {
		return modelMapper.map(dto, LoadingTask.class);
	}

	private AgainTask fromDto(AgainTaskDto dto) {
		return modelMapper.map(dto, AgainTask.class);
	}

//	private TransportInspectTask fromDto(TransportInspectTaskDto dto) {
//		return modelMapper.map(dto, TransportInspectTask.class);
//	}


	@Override
	public void yzlTaskCreate(AgainTaskPrepareDto dto) {
		Date currentDate = new Date();
		// 1设置默认信息
		dto.setGmtCreate(currentDate);
		dto.setRawStatus(LoadingTaskDto.rawStatus_0);
		AgainTaskPrepare task = fromDto(dto);
		againTaskPrepareService.saveOrUpdate(task);
		// 2分解桶
		Map<Integer, Integer> splittings = new LinkedHashMap<Integer, Integer>();
		DecompositionSchemeParam decompositionSchemeParam = new DecompositionSchemeParam();
		decompositionSchemeParam.setEquipmentCode(task.getEquipmentCode());
		decompositionSchemeParam.setProductModeCode(task.getProductCode());
		decompositionSchemeParam.setWeight(task.getAgainWeigth());
		decompositionSchemeParam.setType(1);
		//默认取段复投
		decompositionSchemeParam.setRepeatTimes(dto.getAgainNum());
		decompositionSchemeParam.setIsFillEnd(0);
		FormulaSchemeData formulaSchemeData = formulaSchemeOutService.decompositionScheme(decompositionSchemeParam);
		if (formulaSchemeData == null) {
			throw new BusinessException("未获取到桶分解数据！");
		}
		for (FormulaSchemeData.FormulaSchemeDataDetail schemeData : formulaSchemeData.getDetail()) {
			splittings.put(schemeData.getIndex(), schemeData.getWeight().intValue());
		}

		// 保存桶分解数据
		List<ProductionFurnaceMaterialSplit> splitList = new ArrayList<>();
		for (FormulaSchemeData.FormulaSchemeDataDetail schemeData : formulaSchemeData.getDetail()) {
			for (FormulaSchemeData.LoadingDetail detail : schemeData.getLoadingDetails()) {
				ProductionFurnaceMaterialSplit split = new ProductionFurnaceMaterialSplit();
				split.setEquipmentCode(task.getEquipmentCode());
				split.setLotNo(task.getLotNo());
				split.setRawType(3);
				split.setAgainNum(null);//区分预装料不让正常装料任务查询到此数据
				split.setProductCode(task.getProductCode());
				split.setTaskId(task.getId());
				split.setSplitInfo(formulaSchemeData, schemeData, detail);
				splitList.add(split);
			}
		}

		// 更新桶分解记录数据
		splitService.deleteByTaskIdAndRawType(task.getId(), 3);
		splitService.saveAll(splitList);

		// 复投任务关联配方方案和重量方案
		task.setRecipeId(formulaSchemeData.getSchemeId());
		task.setWeigthId(formulaSchemeData.getWeightSchemeId());
		//取前桶分解数据前两桶生成预装料任务
		String pailNum = "";
		String taskWeigths = "";
		int againPailNum = 0;
		BigDecimal freightWeigth = BigDecimal.ZERO;
		List<ProductionFurnaceMaterialSplit> collect = splitList.stream().
				filter(v -> v.getBucketIndex() == 1 || v.getBucketIndex() == 2).
				sorted(Comparator.comparing(ProductionFurnaceMaterialSplit::getBucketIndex))
				.collect(Collectors.toList());
		for (int i = 0; i < collect.size(); i++) {
			if(i == 0){
				pailNum += collect.get(i).getBucketIndex();
				taskWeigths += collect.get(i).getBucketWeight();
			} else {
				pailNum += "," + collect.get(i).getBucketIndex();
				taskWeigths += "," + collect.get(i).getBucketWeight();
			}
			againPailNum ++;
		}
		task.setAgainPailNum(againPailNum);
		task.setFreightWeigth(freightWeigth);
		task.setNum(againPailNum);
		task.setPailNum(pailNum);
		task.setTaskWeigths(taskWeigths);
		task.setStartTime(currentDate);

		againTaskPrepareService.saveOrUpdate(task);
		if (GlobalSwitch.enable(GlobalSwitchNamespace.NAMESPACE_AUTOMATION, "CanningMaterial", false)) {
			//下发生产任务接口 装罐料下发
			mesToMcsService.issueMoInterface(task);
		}

	}

	private AgainTaskPrepare fromDto(AgainTaskPrepareDto dto) {
		return modelMapper.map(dto, AgainTaskPrepare.class);
	}
}
