package com.paic.pad.info.monitor.res.biz.services.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.paic.pad.info.common.biz.services.BussinessServices;
import com.paic.pad.info.common.biz.services.CommSysParamService;
import com.paic.pad.info.common.biz.services.WorkCalendarService;
import com.paic.pad.info.common.dto.BussinessDTO;
import com.paic.pad.info.common.utils.CommonUtils;
import com.paic.pad.info.common.utils.DateUtils;
import com.paic.pad.info.common.utils.SystemConstant;
import com.paic.pad.info.monitor.res.biz.services.MessageBoardQuartzService;
import com.paic.pad.info.tmr.board.biz.dao.po.MsgBoardInstructorPO;
import com.paic.pad.info.tmr.board.biz.services.MsgBoardInstructorServices;
import com.paic.pad.info.tmr.board.biz.services.MsgBoardRegistrationServices;
import com.paic.pad.info.tmr.board.biz.services.MsgBoardScheduleServices;
import com.paic.pad.info.tmr.board.biz.services.ScheduleHistoryServices;
import com.paic.pad.info.tmr.board.dto.MsgBoardInstructorDTO;
import com.paic.pad.info.tmr.board.dto.MsgBoardScheduleDTO;
import com.paic.pad.info.tmr.board.dto.ScheduleHistoryDTO;
import com.paic.pad.info.tmr.message.biz.dao.po.MessagePO;
import com.paic.pad.info.tmr.message.biz.services.MessageService;
import com.paic.pad.info.tmr.message.dto.MessageDTO;
import com.paic.pafa.app.biz.service.BaseService;
import com.paic.pafa.app.biz.service.BusinessServiceException;

/**
 * 留言板定时任务
 * 
 * @author hailei015
 * 
 */
@Component("messageBoardQuartzService")
public class MessageBoardQuartzServiceImpl extends BaseService implements MessageBoardQuartzService {
	private final Log logger = LogFactory.getLog(this.getClass());
	
	@Autowired
	private CommSysParamService commSysParamService;
	@Autowired
	private MsgBoardRegistrationServices msgBoardRegistrationServices;
	@Autowired
	private WorkCalendarService workCalendarService;
	@Autowired
	private ScheduleHistoryServices scheduleHistoryServices;
	@Autowired
	private MsgBoardScheduleServices msgBoardScheduleServices;
	@Autowired
	private MsgBoardInstructorServices msgBoardInstructorServices;
	@Autowired
	private MessageService messageService;
	@Autowired
	private BussinessServices bussinessServices;

	private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

	@Override
	public String executeMsgBoardScheduleAndRemindDisableJob() {
		String message = "";
		try {
			List<BussinessDTO> list = bussinessServices.getAllBussinessList();
			message = executeMsgBoardScheduleAndRemindDisableJobByAdmin(list);
		}
		catch (Exception e) {
			message = "查询业务线出现异常";
			logger.error("executeMsgBoardScheduleAndRemindJob: 查询业务线出现异常",e);
		}
		
		return message;
	}

	/**
	 * 给出一个日期判断它是否有排班, 如果没有则将最小的日期对象排成这个班
	 * 
	 * @param date
	 * @throws BusinessServiceException 
	 */
	private void msgBoardScheduleByDate(String date, String bizSeries) throws Exception {
		boolean canSchedule = true;// 默认需要排班
		MsgBoardScheduleDTO dto = msgBoardScheduleServices.getMsgBoardScheduleByDate(date, bizSeries);
		
		if (dto != null) {
			// 假如这天已经被排班了
			if (dto.getIsDisable().equals(MsgBoardInstructorPO.DISABLE_NO)) {
				canSchedule = false;
				logger.info("msgBoardScheduleByDate: 日期 " + date + "已有辅导员, 无需排班!");
			}
		}
		
		if (canSchedule) {
			String minDate = msgBoardScheduleServices.getMinMsgBoardScheduleDate(bizSeries);
			
			if (StringUtils.isNotEmpty(minDate)) {
				MsgBoardScheduleDTO toScheduleDto = msgBoardScheduleServices.getMsgBoardScheduleByDate(minDate, bizSeries);
				toScheduleDto.setScheduleDate(DateUtils.toDate(date));
				msgBoardScheduleServices.updateMsgBoardSchedule(toScheduleDto);

				MsgBoardInstructorDTO msgDto = new MsgBoardInstructorDTO();
				msgDto.setUmId(toScheduleDto.getUmId());
				msgDto.setIsDisable(MsgBoardInstructorPO.DISABLE_NO);
				msgBoardInstructorServices.updateMsgBoardInstructor(msgDto);
				logger.info("msgBoardScheduleByDate: 成功将" + msgDto.getUmId() + "排班, 其上次值班日期为:" + minDate + ", 新排班日期为:" + date);
			}
		}
	}

	/**
	 * 根据业务线执行留言板定时任务
	 * 
	 * @param bizSeries
	 */
	@Transactional
	private String executeMsgBoardJobs(String bizSeries) throws Exception {
		String message = "执行成功!";
		// 获得当前日期
		String today = DateUtils.getTodayDate(format);
		String yesterday = DateUtils.getDate(today, -1, format);

		// 今天的值班记录对象
		MsgBoardScheduleDTO dto = msgBoardScheduleServices.getMsgBoardScheduleByDate(yesterday, bizSeries);
		
		if (dto != null) {
			// 假如today是周五 那么 nextDay 不应该是周六 而应该是个工作日 (如周一才正确)
			Date nextWorkday = workCalendarService.getSEQWorkDayByPramDate(today, bizSeries);
			
			if (nextWorkday != null) {
				today = DateUtils.toString(nextWorkday);
			} 
			else {
				message = "执行失败, 无法获取下一个工作日!";
				logger.error("executeMsgBoardJobs: " + message);
				return message;
			}
			
			/************************ 执行内容 1.今天值班完了 插入一条流水记录 **************************************/
			ScheduleHistoryDTO scheduleHistoryDTO = new ScheduleHistoryDTO();
			scheduleHistoryDTO.setScheduleDate(dto.getScheduleDate());
			scheduleHistoryDTO.setUmId(dto.getUmId());
			scheduleHistoryDTO.setLoginUser("MsgBoardJob");
			scheduleHistoryServices.insertScheduleHistory(scheduleHistoryDTO);
			logger.info("executeMsgBoardJobs: 成功插入" + yesterday + "的值班记录, 辅导员:" + dto.getUmId());

			/************************ 执行内容 2.修改当天值班人为可禁用状态,可以重新排班状态 **************************************/
			MsgBoardInstructorDTO msgBoardInstructorDTO = new MsgBoardInstructorDTO();
			msgBoardInstructorDTO.setIsDisable(MsgBoardInstructorPO.DISABLE_YES);
			msgBoardInstructorDTO.setUmId(dto.getUmId());
			msgBoardInstructorServices.updateMsgBoardInstructor(msgBoardInstructorDTO);
			//将今天之前未值班的人全部置为已值班
			msgBoardInstructorServices.changeInstructorDisableBeforeToday(bizSeries);
			logger.info("executeMsgBoardJobs: 成功修改" + yesterday + "的辅导员" + dto.getUmId() + "为已值班状态");

			/************************ 执行内容 3.排班 **************************************/
			Integer personCount = msgBoardScheduleServices.getMsgBoardScheduleCount(bizSeries);
			String oneWorkDay = getWorkdayAfter(1, yesterday, bizSeries);// 排出 今天之后的   1天后的工作日
			String twoWorkDay = getWorkdayAfter(1, today, bizSeries); // 提醒1天提醒       排2天后的班
			String threeWorkDay = getWorkdayAfter(3, yesterday, bizSeries);// 排出 今天之后的    3天后的工作日
			String fourWorkDay = getWorkdayAfter(3, today, bizSeries); // 支持3天提醒// 排4天后的班
			

			if ((personCount != null) && (personCount.intValue() > 0)) {
				// 人数至大于4人才能走3天提醒流程和1天提醒
				if (personCount.intValue() >= 4) {
					this.msgBoardScheduleByDate(oneWorkDay, bizSeries);
					this.msgBoardScheduleByDate(twoWorkDay, bizSeries);
					this.msgBoardScheduleByDate(threeWorkDay, bizSeries);
					this.msgBoardScheduleByDate(fourWorkDay, bizSeries);
				}
				// 人数小于4大于2人 只走 1天提醒
				else if ((personCount.intValue() <= 3) && (personCount.intValue() >= 2)) {
					this.msgBoardScheduleByDate(oneWorkDay, bizSeries);
					this.msgBoardScheduleByDate(twoWorkDay, bizSeries);
				}
				// 假如只有1人 只能排班无法 提醒
				else if (personCount.intValue() == 1) {
					this.msgBoardScheduleByDate(oneWorkDay, bizSeries);
				}
			}
			else {
				message = "目前没有留言板辅导员,无法排班!";
				logger.info("executeMsgBoardJobs:" + message);
			}

			/************************ 执行内容 4.消息提醒 **************************************/
			String sysNameStr = commSysParamService.queryParamValueByBizSeriesAndParamKey(bizSeries, SystemConstant.MESSAGE_BOARD_SYSADMIN_NAME);
			String sysName = StringUtils.isEmpty(sysNameStr) ? "未知" : sysNameStr;
			String sysTelStr = commSysParamService.queryParamValueByBizSeriesAndParamKey(bizSeries, SystemConstant.MESSAGE_BOARD_SYSADMIN_TEL);
			String sysTel = StringUtils.isEmpty(sysTelStr) ? "未知" : sysTelStr;

			MessageDTO messageDTO = new MessageDTO();
			messageDTO.setMessageTitle("留言板辅导员提醒");
			messageDTO.setMessageType(MessagePO.MESSAGE_BOARD);
			messageDTO.setSource(MessagePO.MESSAGE_SOURCE_TMR);
			messageDTO.setStatus(0);
			messageDTO.setMessageFrom(MessagePO.MESSAGE_SYS_FROM);
			messageDTO.setSubmitDate(new Date());
			messageDTO.setUmId("padinfodata");

			MsgBoardScheduleDTO msgDtoThree = msgBoardScheduleServices.getMsgBoardScheduleByDate(fourWorkDay, bizSeries);
			
			if (msgDtoThree != null) {
				messageDTO.setMessageTo(msgDtoThree.getUmId());
				messageDTO.setMessageContent(fourWorkDay + "您将担任留言板值班人,若当天休假请提前联系管理员" + sysName + "(联系方式:" + sysTel + ")安排调整。");
				messageService.addMessage(messageDTO);
				logger.info("executeMsgBoardJobs:成功发送三天后的提醒 " + msgDtoThree.getUmId() + " 值班日期:" + fourWorkDay);
			}

			MsgBoardScheduleDTO msgDtoTomorrow = msgBoardScheduleServices.getMsgBoardScheduleByDate(twoWorkDay, bizSeries);
			
			if (msgDtoTomorrow != null) {
				messageDTO.setMessageTo(msgDtoTomorrow.getUmId());
				messageDTO.setMessageContent(twoWorkDay + "您将担任留言板值班人,若当天休假请提前联系管理员" + sysName + "(联系方式:" + sysTel + ")安排调整。");
				messageService.addMessage(messageDTO);
				logger.info("executeMsgBoardJobs:成功发送一天后的提醒 " + msgDtoTomorrow.getUmId() + " 值班日期:" + twoWorkDay);
			}
		} 
		else {
			logger.info("executeMsgBoardJobs:昨天没有值班人无需排班!");
		}
		
		return message;
	}

	/**
	 * 给定一个日期获得这个日期 指定天数后的工作日期(非工作日自动过滤) 如传入周四想得到3天后的日期则返回下周二
	 * 
	 * @param today
	 * @return
	 * @throws BusinessServiceException
	 */
	private String getWorkdayAfter(int laterDay, String today, String umBizSeries) throws BusinessServiceException {
		String threeDay = null;
		
		for (int i = 1; i <= laterDay; i++) {
			String oneDay = DateUtils.getDate(today, +1, format);
			today = DateUtils.toString(workCalendarService.getSEQWorkDayByPramDate(oneDay, umBizSeries));
			threeDay = today;
		}

		return threeDay;
	}
	
	@Override
	public String executeMsgBoardScheduleAndRemindDisableJobByAdmin(List<BussinessDTO> list) {
		String message = " 留言板排班";
		boolean isGetLock = false;
		
		try {
			// N为目前没人执行 Y表示已经在执行 如果 N 能改为Y 证明目前没人执行。 默认执行完都会改为N
			// 将N改为Y 如果修改条数大于0说明成功, 目前没人
			int updatedCount = commSysParamService.updateParamValueByParamKey(SystemConstant.MESSAGE_SCHEDULE_QUARTZ_IS_STARTED, SystemConstant.NO, SystemConstant.YES, null);
			boolean isQuartzStarted = (updatedCount <= 0);
	
			if (isQuartzStarted) {
				message = "已在执行,无法重执行!";
				logger.info("executeMsgBoardScheduleAndRemindJob: " + message);
				return message;
			}
			else {
				isGetLock = true;
			}
			
			StopWatch watch = new StopWatch();
			watch.start();
			logger.info("executeMsgBoardScheduleAndRemindJob: 任务开始");
			
			if (CommonUtils.listNotNull(list)) {
				// 判断该业务线下留言板辅导员功能是否开启(Y:启用 或者 N:禁用)
				Map<String, String> map = commSysParamService.queryParamValuesMapByParamKey(SystemConstant.ENABLE_FUN_INSTRUCTOR);
				
				logger.info("executeMsgBoardScheduleAndRemindJob: 目前可以执行的业务线为(" + list.size() + ")条");
				
				for (int i = 0; i < list.size(); i++) {
					BussinessDTO bussinessDTO = list.get(i);
					String bizSeri = bussinessDTO.getBizSeries();
					String enableFunInstructor = map.get(bizSeri);
					
					//功能开关开启
					if (StringUtils.isNotEmpty(enableFunInstructor) && enableFunInstructor.equals(SystemConstant.YES)) {
						try {
							//获得上一次任务执行日期
							String lastQuartzDate = commSysParamService.queryParamValueByBizSeriesAndParamKeyWithoutCache(bizSeri, SystemConstant.MESSAGE_SCHEDULE_QUARTZ_DEAL_TIME);
							lastQuartzDate = StringUtils.isNotEmpty(lastQuartzDate) ? lastQuartzDate : "2000-01-01";
							// 获得当前日期
							String today = DateUtils.getTodayDate(format);
							
							boolean isDataLatest = (lastQuartzDate.compareTo(today) >= 0);

							if (isDataLatest) {
								message = message +"业务线[" + bizSeri + "] 已执行过排班, 无法重复执行!\n";
								logger.info("executeMsgBoardScheduleAndRemindJob:" + message);
								continue;
							}
							
							logger.info("executeMsgBoardScheduleAndRemindJob: 开始业务线[" + bizSeri + "]排班");
							
							String bizMsg = this.executeMsgBoardJobs(bizSeri);
							
							message = message + "\n [" + bizSeri + "]排班 " + bizMsg;
							logger.info("executeMsgBoardScheduleAndRemindJob: 完成业务线[" + bizSeri + "]排班");
							
							commSysParamService.updateParamValueByParamKey(SystemConstant.MESSAGE_SCHEDULE_QUARTZ_DEAL_TIME, null, today, bussinessDTO.getBussinessId());
							
							logger.info("executeMsgBoardScheduleAndRemindJob:业务线[" + bizSeri + "]执行日期更新到" + today + "成功");

							
						}
						catch (Exception e) {
							message = message + "\n [" + bizSeri + "]排班 出现异常";
							logger.error("executeMsgBoardScheduleAndRemindJob: 业务线[" + bizSeri + "]排班  出现异常",e);
						}
					}
					else {
						message = message + "\n [" + bizSeri + "]排班 功能开关没有开启!" ;
					}
				}
			}
			
			//处理完等待5分钟, 防止其他服务器重复执行
			Thread.sleep(5 * 60 * 1000);
			
			watch.stop();
			logger.info("executeMsgBoardScheduleAndRemindJob: 任务完成, 执行花费时间为:" + watch.getTime());

		}
		catch (Exception e) {
			message = "执行发生异常!执行失败!请联系管理员!";
			logger.error("executeMsgBoardScheduleAndRemindDisableJob: " + message, e);
		}
		finally {
			// 所有任务执行完毕后打开开关让下次可以进入执行
			try {
				if(isGetLock) {
					commSysParamService.updateParamValueByParamKey(SystemConstant.MESSAGE_SCHEDULE_QUARTZ_IS_STARTED, SystemConstant.YES, SystemConstant.NO, null);
				}
			}
			catch (BusinessServiceException e) {
				logger.error("executeMsgBoardScheduleAndRemindJob: 重置MESSAGE_SCHEDULE_QUARTZ_IS_STARTED 失败", e);
			}
		}

		return message;
	}
}