package com.yihu.wlyy.task;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.yihu.wlyy.entity.follow.FollowUpItemRecord;
import com.yihu.wlyy.entity.follow.FollowUpItemRecordQuestion;
import com.yihu.wlyy.entity.follow.FollowUpItemRecordQuestionOption;
import com.yihu.wlyy.entity.follow.FollowUpPlan;
import com.yihu.wlyy.entity.follow.FollowUpPlanStage;
import com.yihu.wlyy.entity.follow.FollowUpPlanStageItem;
import com.yihu.wlyy.entity.follow.FollowUpPlanStageItemQuestion;
import com.yihu.wlyy.repository.followup.FollowUpItemRecordDao;
import com.yihu.wlyy.repository.followup.FollowUpItemRecordQuestionDao;
import com.yihu.wlyy.repository.followup.FollowUpItemRecordQuestionOptionDao;
import com.yihu.wlyy.repository.followup.FollowUpPlanDao;
import com.yihu.wlyy.repository.followup.FollowUpPlanStageDao;
import com.yihu.wlyy.repository.followup.FollowUpPlanStageItemDao;
import com.yihu.wlyy.repository.followup.FollowUpPlanStageItemQuestionDao;
import com.yihu.wlyy.util.DateUtil;
import com.yihu.wlyy.util.MessageType;

@Component("followUpTask")
@Service
@Transactional(rollbackOn = Exception.class)
public class FollowUpTask {

	private static Logger logger = LoggerFactory.getLogger(FollowUpTask.class);

	@Autowired
	private FollowUpPlanDao followUpPlanDao;
	@Autowired
	private FollowUpPlanStageDao followUpPlanStageDao;
	@Autowired
	private FollowUpPlanStageItemDao followUpPlanStageItemDao;
	@Autowired
	private FollowUpPlanStageItemQuestionDao followUpPlanStageItemQuestionDao;
	@Autowired
	private FollowUpItemRecordDao followUpItemRecordDao;
	@Autowired
	private FollowUpItemRecordQuestionDao followUpItemRecordQuestionDao;
	@Autowired
	private FollowUpItemRecordQuestionOptionDao followUpItemRecordQuestionOptionDao;

	public void push() {

		logger.info("begin push");

		List<FollowUpPlanStageItem> items = followUpPlanStageItemDao.findByNextPushDate(DateUtil.getNowDateShort());
		if (items == null) {
			return;
		}
		for (FollowUpPlanStageItem item : items) {
			if (item == null) {
				continue;
			}
			try {
				// 查询计划信息
				FollowUpPlan plan = followUpPlanDao.findByCode(item.getPlan());
				// 查询阶段信息
				FollowUpPlanStage stage = followUpPlanStageDao.findByCode(item.getStage());

				if (plan.getStatus() == -1) {
					// 计划已暂停
					continue;
				}
				if (stage.getStatus() == -1) {
					// 阶段已暂停
					continue;
				}

				// 状态反更新，防止出现数据不同步
				if (!checkStatus(plan, stage)) {
					// 状态不同步，同步状态位，不再处理该随访项
					continue;
				}

				// 判断定时阶段是否到期
				if (checkStageEndDate(plan, stage)) {
					continue;
				}

				// 推送随访记录
				doPush(plan, stage, item);
			} catch (Exception e) {
				e.printStackTrace();
				logger.error("FollowUpTask push error:", e);
			}
		}
	}

	/**
	 * 校验随访计划的状态是否同步
	 * @param plan 随访计划
	 * @param stage 随访阶段
	 * @return
	 */
	private boolean checkStatus(FollowUpPlan plan, FollowUpPlanStage stage) {
		if (plan.getStatus() == 1) {
			// 如果计划已结束，关闭所有的随访阶段和随访项
			followUpPlanStageDao.updateStatusByPlan(2, plan.getCode());
			followUpPlanStageItemDao.updateStatusByPlan(2, plan.getCode());
			return false;
		} else if (stage.getStatus() == 2) {
			// 如果随访阶段已结束，关闭所有的随访项
			followUpPlanStageItemDao.updateStatusByStage(2, stage.getCode());
			return false;
		}
		return true;
	}

	/**
	 * 判断定时随访阶段是否到期
	 * @param plan
	 * @param stage
	 * @return
	 */
	private boolean checkStageEndDate(FollowUpPlan plan, FollowUpPlanStage stage) {
		if (stage.getType() == 1 && stage.getEndDate().compareTo(DateUtil.getNowDateShort()) <= 0) {
			// 阶段定时已到，更新阶段状态为已完成
			stage.setStatus(2);
			followUpPlanStageDao.save(stage);
			// 更新阶段下随访项为已完成
			followUpPlanStageItemDao.updateStatusByStage(2, stage.getCode());
			// 查询下一计划阶段
			FollowUpPlanStage nextStage = followUpPlanStageDao.findNextStage(plan.getCode(), stage.getSeq() + 1);
			if (nextStage == null) {
				// 没有下一阶段，表示计划已完成
				plan.setStatus(1);
				followUpPlanDao.save(plan);
			} else {
				// 开启下一阶段
				nextStage.setStatus(1);
				followUpPlanStageDao.save(nextStage);
				// 查询阶段下随访项列表
				List<FollowUpPlanStageItem> itemList = followUpPlanStageItemDao.findByStage(nextStage.getCode());
				for (FollowUpPlanStageItem tempItem : itemList) {
					if (tempItem == null) {
						continue;
					}
					if (tempItem.getPushBegin().compareTo(DateUtil.getNowDateShort()) <= 0) {
						// 已到推送日期,推送随访记录
						doPush(plan, nextStage, tempItem);
					}
				}
			}
			return true;
		}
		return false;
	}

	/**
	 * 推送随访记录
	 * @param plan 随访计划
	 * @param stage 随访计划阶段
	 * @param item 随访计划阶段随访项
	 */
	private void doPush(FollowUpPlan plan, FollowUpPlanStage stage, FollowUpPlanStageItem item) {
		// 推送次数+1
		item.setTimes(item.getTimes() + 1);
		// 生成随访记录
		FollowUpItemRecord record = new FollowUpItemRecord();
		record.setCode(getCode());
		record.setCzrq(new Date());
		record.setItem(item.getCode());
		record.setPlan(plan.getCode());
		record.setStage(stage.getCode());
		// 未作答
		record.setStatus(0);
		record.setTitle(item.getTitle());
		record.setType(item.getType());

		// 查询随访项问题列表
		List<FollowUpItemRecordQuestion> recordQuestionList = new ArrayList<FollowUpItemRecordQuestion>();
		// 随访记录问题选项列表
		List<FollowUpItemRecordQuestionOption> recordQuestionOptionList = new ArrayList<FollowUpItemRecordQuestionOption>();
		// 随访记录问题列表
		List<FollowUpPlanStageItemQuestion> questions = followUpPlanStageItemQuestionDao.findByItem(item.getCode());
		// 生成随访问题
		for (FollowUpPlanStageItemQuestion question : questions) {
			if (question == null) {
				continue;
			}
			// 新的问题
			FollowUpItemRecordQuestion recordQuestion = new FollowUpItemRecordQuestion();
			recordQuestion.setCode(question.getCode());
			recordQuestion.setIndex(question.getIndex());
			recordQuestion.setItem(item.getCode());
			recordQuestion.setPlan(plan.getCode());
			recordQuestion.setRecord(record.getCode());
			recordQuestion.setStage(stage.getCode());
			recordQuestion.setTitle(question.getTitle());
			recordQuestion.setType(question.getType());
			recordQuestionList.add(recordQuestion);

			// 新的选项
			if (StringUtils.isNotEmpty(question.getOptions())) {
				JSONArray options = new JSONArray(question.getOptions());
				for (int i = 0; i < options.length(); i++) {
					JSONObject json = options.getJSONObject(i);
					// 新的问题选项
					FollowUpItemRecordQuestionOption option = new FollowUpItemRecordQuestionOption();
					option.setCode(getCode());
					option.setDes(json.getString("des"));
					option.setItem(item.getCode());
					option.setPlan(plan.getCode());
					option.setQuestion(question.getCode());
					option.setRecord(record.getCode());
					option.setStage(stage.getCode());
					// 添加到选项列表
					recordQuestionOptionList.add(option);
				}
			}
		}

		// 计算下一次推送日期
		Date nextPushDate = null;
		if (item.getPushCycleUnit() == 1 || item.getPushCycleUnit() == 2) {
			// 按天数再推算一下个推送日期
			int days = item.getPushCycle();
			if (item.getPushCycleUnit() == 2) {
				// 1周7天
				days = item.getPushCycle() * 7;
			}
			// 设置下一次推送日期
			nextPushDate = DateUtil.strToDateShort(DateUtil.getNextDay(DateUtil.getNowDateShort(), days));
		} else {
			// 按月推送
			nextPushDate = DateUtil.strToDateShort(DateUtil.getNextMonth(DateUtil.getNowDateShort(), item.getPushCycle()));
		}
		// 随访项是否已完成
		boolean isFinish = false;
		if (stage.getType() == 1 && stage.getEndDate().compareTo(nextPushDate) <= 0) {
			// 下次推送已晚于阶段结束日期
			isFinish = true;
			// 设置随访项已完成
			item.setStatus(2);
			item.setNextPushDate(nextPushDate);
		} else {
			if (item.getPushType() == 1 && nextPushDate.before(item.getPushEnd())) {
				// 按时间推送且未过推送结束日期
				item.setNextPushDate(nextPushDate);
			} else if (item.getPushType() == 2 && item.getPushTimes() > item.getTimes()) {
				// 接次数推送且推送次数大于已推送次数
				item.setNextPushDate(nextPushDate);
			} else {
				isFinish = true;
				// 设置随访项已完成
				item.setStatus(2);
				item.setNextPushDate(nextPushDate);
			}
		}

		if (item.getType() == 1) {
			// 问卷随访数+1
			plan.setWjAmount(plan.getWjAmount() + 1);
			// followUpPlanDao.increaseWjAmount(plan.getCode());
		} else if (item.getType() == 2) {
			// 体测随访数+1
			plan.setTcAmount(plan.getTcAmount() + 1);
			// followUpPlanDao.increaseTcAmount(plan.getCode());
		}
		followUpPlanDao.save(plan);
		// 更新阶段对象
		followUpPlanStageItemDao.save(item);
		// 保存问题选项到数据库
		followUpItemRecordQuestionOptionDao.save(recordQuestionOptionList);
		// 保存问题到数据库
		followUpItemRecordQuestionDao.save(recordQuestionList);
		// 保存记录到数据库
		followUpItemRecordDao.save(record);

		// 发送推送消息给患者端
		PushMsgTask.getInstance().put(plan.getPatient(), MessageType.MESSAGE_TYPE_PATIENT_NEW_FOLLOW_UP.P_FU_01.name(), MessageType.MESSAGE_TYPE_PATIENT_NEW_FOLLOW_UP.随访计划.name(), MessageType.MESSAGE_TYPE_PATIENT_NEW_FOLLOW_UP.您有新的随访计划.name(), record.getCode());

		// 随访项已结束
		if (isFinish) {
			// 查询是否还有未完成的随访项
			int amount = followUpPlanStageItemDao.hasOtherUnfinish(stage.getCode(), item.getCode());
			if (amount == 0) {
				// 全部随访项已完成，更新随访阶段状态为已完成
				stage.setStatus(2);
				followUpPlanStageDao.save(stage);
				// 查询是否还有未完成的随访阶段
				FollowUpPlanStage nextStage = followUpPlanStageDao.findNextStage(plan.getCode(), stage.getSeq() + 1);
				if (nextStage == null) {
					// 所有随访阶段已完成，更新随访计划为已完成
					plan.setStatus(1);
					followUpPlanDao.save(plan);
				} else {
					// 开启下一随访阶段
					nextStage.setStatus(1);
					followUpPlanStageDao.save(nextStage);
					// 查询阶段下随访项列表
					List<FollowUpPlanStageItem> itemList = followUpPlanStageItemDao.findByStage(nextStage.getCode());
					for (FollowUpPlanStageItem tempItem : itemList) {
						if (tempItem == null) {
							continue;
						}
						if (tempItem.getPushBegin().compareTo(DateUtil.getNowDateShort()) <= 0) {
							// 已到推送日期,推送随访记录
							tempItem.setStatus(1);
							doPush(plan, nextStage, tempItem);
						}
					}
				}
			}
		}
	}

	private String getCode() {
		return UUID.randomUUID().toString().replaceAll("-", "");
	}

}
