package com.yeejoin.amos.maintenance.quartz;

import com.alibaba.fastjson.JSON;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.MessageModel;
import com.yeejoin.amos.maintenance.business.constants.XJConstant;
import com.yeejoin.amos.maintenance.business.dao.mapper.CheckMapper;
import com.yeejoin.amos.maintenance.business.dao.mapper.MsgMapper;
import com.yeejoin.amos.maintenance.business.dao.mapper.PlanTaskMapper;
import com.yeejoin.amos.maintenance.business.dao.repository.*;
import com.yeejoin.amos.maintenance.business.entity.mybatis.PlanTaskPointInputItemBo;
import com.yeejoin.amos.maintenance.business.param.MsgConfigParam;
import com.yeejoin.amos.maintenance.business.service.intfc.IMessageService;
import com.yeejoin.amos.maintenance.business.util.DateUtil;
import com.yeejoin.amos.maintenance.business.util.Toke;
import com.yeejoin.amos.maintenance.common.enums.*;
import com.yeejoin.amos.maintenance.core.async.AsyncTask;
import com.yeejoin.amos.maintenance.dao.entity.*;
import com.yeejoin.amos.maintenance.feign.RemoteSecurityService;
import com.yeejoin.amos.maintenance.mqtt.MqttGateway;
import org.quartz.Job;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.typroject.tyboot.core.foundation.context.RequestContext;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service("jobService")
public class JobService implements IJobService {

    private final Logger log = LoggerFactory.getLogger(JobService.class);

    @Autowired
    private ITaskDao iTaskDao;

    @Autowired
    private IPlanTaskDao iPlanTaskDao;


    @Autowired
    private IPlanTaskDetailDao iPlanTaskDetailDao;

    @Autowired
    private IMessageService messageService;

    @Autowired
    private PlanTaskMapper planTaskMapper;

    @Autowired
    private ICheckDao iCheckDao;

    @Autowired
    private ICheckInputDao iCheckInputDao;

    @Autowired
    private AsyncTask asyncTask;

    @Autowired
    private IMsgDao iMsgDao;

    @Autowired
    private ITaskFeedbackDao taskFeedbackDao;

    @Autowired
    private RemoteSecurityService remoteSecurityService;

    @Value("${amosRefresh.patrol.topic}")
    private String patrolTopic;

    @Override
    @Transactional
    public void initScheduler() {
        // TODO Auto-generated method stub
        log.debug("======================initScheduler===========================");
        initTaskJob();
        initPlanTaskJob();
        initMsgJob();
    }

    @Override
    public void addJob(String name, String jobType, long id, Date time) {
        String jobName = name + "-" + jobType + "-" + id;
        if (time != null && time.getTime() > new Date().getTime()) {
            SimpleDateFormat formatter = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
            String cronDate = formatter.format(time);
            log.debug("addJob==jobName==" + jobName);
            QuartzManager.addJob(jobName, jobType, id, getJobInstance(name).getClass(), cronDate);
        }
    }

    /**
     * 初始化任务job
     */
    private void initTaskJob() {
        List<Task> taskList = iTaskDao.findAllByStatus(TaskStatusEnum.UNDERWAY.getValue());
        List<Task> updateTask = new ArrayList<Task>();
        taskList.forEach(task -> {
            Date finishTime = task.getFinishTime();
            if (finishTime != null) {
                if (finishTime.getTime() > new Date().getTime()) {
                    taskAddJob(task);
                } else {
                    task.setStatus(TaskStatusEnum.OVERTIME.getValue());
                    updateTask.add(task);
                }
            }
        });
        iTaskDao.saveAll(updateTask);
    }

    /**
     * 初始化计划执行job
     */
    private void initPlanTaskJob() {
        List<Integer> statusList = new ArrayList<Integer>();
        statusList.add(PlanTaskFinishStatusEnum.NOTSTARTED.getValue());
        statusList.add(PlanTaskFinishStatusEnum.UNDERWAY.getValue());
        List<PlanTask> planTaskList = iPlanTaskDao.findAllByFinishStatusIn(statusList);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        planTaskList.forEach(planTask -> {
            try {
                Date beginTime = sdf.parse(planTask.getBeginTime());
                Date endTime = sdf.parse(planTask.getEndTime());
                long timestamp = new Date().getTime();
                if (PlanTaskFinishStatusEnum.NOTSTARTED.getValue() == planTask.getFinishStatus()) {
                    if (beginTime.getTime() > timestamp) {
                        planTaskAddJob(planTask);

                    } else if (beginTime.getTime() < timestamp && endTime.getTime() > timestamp) {
                        planTask.setFinishStatus(PlanTaskFinishStatusEnum.UNDERWAY.getValue());
                        iPlanTaskDao.save(planTask);
                        planTaskAddJob(planTask);
                    } else if (endTime.getTime() < timestamp) {
                        updatePlanTaskStatus(planTask, PlanTaskFinishStatusEnum.OVERTIME.getValue());
                    }
                } else {
                    if (endTime.getTime() < timestamp) {
                        updatePlanTaskStatus(planTask, PlanTaskFinishStatusEnum.OVERTIME.getValue());
                    } else {
                        planTaskAddJob(planTask);
                    }
                }
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                log.debug(e.getMessage());
                e.printStackTrace();
            }
        });

    }

    private void initMsgJob() {
        List<Msg> msgList = iMsgDao.findAllByIsImmediatelyTrueAndStatus(0);
        if (!msgList.isEmpty()) {
            msgList.forEach(msg -> {
                addJob("msg", XJConstant.MESSAGE_PUSH, msg.getId(), msg.getFixedTime());
            });
        }
    }

    private void updatePlanTaskStatus(PlanTask planTask, int status) {
        planTask.setFinishStatus(status);
        iPlanTaskDao.save(planTask);
        List<PlanTaskDetail> planTaskDetails = iPlanTaskDetailDao.findAllByTaskNoAndStatus(planTask.getId(), PlanTaskDetailStatusEnum.NOTSTARTED.getValue());
        if (!planTaskDetails.isEmpty()) {
            planTaskDetails
                    .forEach(action -> {
                        action.setIsFinish(PlanTaskDetailIsFinishEnum.OVERTIME.getValue());
                        action.setStatus(PlanTaskDetailStatusEnum.OMISSION.getValue());
                        iPlanTaskDetailDao.saveAndFlush(action);
                    });
        }
        if (PlanTaskFinishStatusEnum.OVERTIME.getValue() == status) {
            createOmissionCheckRecord(planTask);
        }
    }

    /**
     * 创建漏检检查记录
     *
     * @param planTask
     */
    private void createOmissionCheckRecord(PlanTask planTask) {
        List<PlanTaskPointInputItemBo> planTaskPointInputItems = planTaskMapper
                .getPlanTaskPointInputItemByPlanTaskId(planTask.getId(), PlanTaskDetailStatusEnum.OMISSION.getValue());
        Map<Long, Check> checkMap = new HashMap<>();
        Set<Long> checkIds = new HashSet<Long>();
        //查询用户名字
        for (PlanTaskPointInputItemBo arg : planTaskPointInputItems) {
            Check check = new Check();
            if (checkMap.get(arg.getPointId()) == null) {
                check.setOrgCode(arg.getOrgCode());
                check.setUserId(planTask.getUserId());
                check.setUserName(planTask.getUserName());
                check.setDepName("");
                check.setPointName(arg.getPointName());
                check.setPointId(arg.getPointId());
                check.setPointNo(arg.getPointNo());
                check.setRiskAndManage(arg.getRiskAndManage());
                check.setBeginTime(planTask.getBeginTime());
                check.setEndTime(planTask.getEndTime());
                check.setBuildingName(arg.getBuildingName());
                check.setAddress(arg.getAddress());
                check.setUploadTime(new Date());
                check.setPlanId(arg.getPlanId());
                check.setPlanName(arg.getPlanName());
                check.setPlanType(arg.getPlanType());
                check.setPlanTaskId(arg.getPlanTaskId());
                check.setPlanTaskDetailId(arg.getPlanTaskDetailId());
                check.setRouteId(arg.getRouteId());
                check.setRouteName(arg.getRouteName());
                check.setCheckTime(arg.getEndTime());
                check.setOwnerId(arg.getOwnerId());
                check.setOwnerName(arg.getOwnerName());
                check.setCompanyId(arg.getCompanyId());
                check.setCompanyName(arg.getCompanyName());
                check.setEquipmentName(arg.getEquipmentName());
                check.setIsOk(CheckStatusEnum.OMISSION.getCode());
                check = iCheckDao.saveAndFlush(check);
                checkMap.put(arg.getPointId(), check);
                checkIds.add(check.getId());
            } else {
                check = checkMap.get(arg.getPointId());
            }
            if (arg.getInputItemId() != null) {
                CheckInput checkInput = new CheckInput();
                checkInput.setCheckId(check.getId());
                checkInput.setInputId(arg.getInputItemId());
                checkInput.setIsOk(CheckStatusEnum.OMISSION.getCode());
                checkInput.setRoutePointItemId(arg.getRoutePointItemId());
                checkInput.setOrderNo(arg.getOrderNo());
                checkInput.setOrgCode(arg.getOrgCode());
                checkInput.setInputName(arg.getInputName());
                checkInput.setPointClassifyId(arg.getClassifyId());
                checkInput.setPointClassifyName(arg.getClassifyName());
                iCheckInputDao.saveAndFlush(checkInput);
            }
            Plan plan = new Plan();
            plan.setId(planTask.getPlanId());
            updateTaskStatus(plan);
        }
    }

    private void updateTaskStatus(Plan plan){
        Toke toke=  remoteSecurityService.getServerToken();
        RequestContext.setToken(toke.getToke());
        RequestContext.setProduct(toke.getProduct());
        RequestContext.setAppKey(toke.getAppKey());
        MessageModel model = new MessageModel();
        model.setRelationId(String.valueOf(plan.getId()));
        model.setMsgType("patrolSystem");
        model.setIsRead(true);
        log.info("修改待办任务参数-->{}", JSON.toJSON(model));
        Systemctl.messageClient.update(model);
    }

    private void removeJob(String jobName) {
        log.debug("removeJob==jobName==" + jobName);
        QuartzManager.removeJob(jobName);
    }

    private Job getJobInstance(String type) {
        switch (type) {
            case "planTask":
                return new PlanTaskJobService();
            case "task":
                return new TaskJobService();
            case "msg":
                return new MsgJobService();
            default:
                return null;
        }
    }

    @Override
    public void taskAddJob(Task task) {
        // TODO Auto-generated method stub
        long taskId = task.getId();
        if (XJConstant.TASK_WARN.equals(task.getIsWarn())) { // 设置为接受报警执行代码
            Date alarmDate = task.getWarnTime();
            addJob("task", XJConstant.MESSAGE_PUSH, taskId, alarmDate);
        }
        addJob("task", XJConstant.STATUS_MONITOR_END, taskId, task.getFinishTime());

    }

    @Override
    @Transactional
    public void taskJobPerform(long taskId, String jobType, String jobName) {
        if (iTaskDao.existsById(taskId)) {
            Task task = iTaskDao.findById(taskId).get();
            Toke toke = remoteSecurityService.getServerToken();
            if (XJConstant.STATUS_MONITOR_END.equals(jobType)) {
                if (TaskStatusEnum.UNDERWAY.getValue() == task.getStatus()) {
                    task.setStatus(TaskStatusEnum.OVERTIME.getValue());
                    iTaskDao.saveAndFlush(task);
                    TaskFeedback taskFeedback = new TaskFeedback();
                    taskFeedback.setUserId(task.getExecutorId());
                    taskFeedback.setMessage("该任务在规定时间内未完成，请核实信息！任务名称： " + task.getTitle() + " 要求完成时间：  "
                            + DateUtil.getDateFormat(task.getFinishTime(), "yyyy-MM-dd HH:mm:ss") + " 发起人："
                            + task.getPublisherName() + " 执行人：" + task.getExecutor());
                    taskFeedback.setCreateDate(new Date());
                    taskFeedback.setUserName(task.getExecutor());
                    taskFeedback.setFeedbackTime(new Date());
                    taskFeedback.setOrgCode(task.getOrgCode());
                    taskFeedback.setTaskId(task.getId());
                    taskFeedback.setMessageType(TaskStatusEnum.OVERTIME.getName());
                    taskFeedback = taskFeedbackDao.save(taskFeedback);
                    try {
                        asyncTask.pushTaskDetailInfoTo3D(toke.getToke(), toke.getProduct(), toke.getAppKey(), taskId); // 超时任务向3D推送
                    } catch (InterruptedException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            } else {
                messageService.pushTaskMessage(toke.getToke(), toke.getProduct(), toke.getAppKey(), task);
            }
        }
        removeJob(jobName);
    }

    @Override
    public void planTaskAddJob(PlanTask planTask) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date endTime = sdf.parse(planTask.getEndTime());
            Date beginTime = sdf.parse(planTask.getBeginTime());
            if (PlanTaskFinishStatusEnum.OVERTIME.getValue() != planTask.getFinishStatus()) {
                // 添加状态监控定时
                int status = planTask.getFinishStatus();
                if (PlanTaskFinishStatusEnum.NOTSTARTED.getValue() == status) {
                    addJob("planTask", XJConstant.STATUS_MONITOR_START, planTask.getId(), beginTime);// 添加监控任务开始时间定时任务
                }
                if (PlanTaskFinishStatusEnum.NOTSTARTED.getValue() == status
                        || PlanTaskFinishStatusEnum.UNDERWAY.getValue() == status) {
                    addJob("planTask", XJConstant.STATUS_MONITOR_END, planTask.getId(), endTime);// 添加监控任务开始结束定时任务
                }
            } else {
                updatePlanTaskStatus(planTask, PlanTaskFinishStatusEnum.OVERTIME.getValue());
            }
        } catch (Exception e) {
            log.error("任务加到定时任务或者更新失败", e);
        }
    }

    @Override
    @Transactional
    public void planTaskJobPerform(long planTaskId, String jobType, String jobName) {

        if (iPlanTaskDao.existsById(planTaskId)) {
            PlanTask planTask = iPlanTaskDao.findById(planTaskId).get();
            if (XJConstant.STATUS_MONITOR_START.equals(jobType)) {
                if (PlanTaskFinishStatusEnum.NOTSTARTED.getValue() == planTask.getFinishStatus()) {
                    planTask.setFinishStatus(PlanTaskFinishStatusEnum.UNDERWAY.getValue());
                    iPlanTaskDao.save(planTask);
                }
            } else if (XJConstant.STATUS_MONITOR_END.equals(jobType)) {
                if (PlanTaskFinishStatusEnum.UNDERWAY.getValue() == planTask.getFinishStatus()) {
                    updatePlanTaskStatus(planTask, PlanTaskFinishStatusEnum.OVERTIME.getValue());
                }
            } else {
                Toke toke = remoteSecurityService.getServerToken();
                messageService.pushPlanTaskMessage(toke.getToke(), toke.getProduct(), toke.getAppKey(), planTask, jobType);
            }
        }
        removeJob(jobName);
    }

    @Override
    public void msgAddJob(Msg msg) {
        addJob("msg", XJConstant.MESSAGE_PUSH, msg.getId(), msg.getFixedTime());
    }

    @Override
    public void msgJobPerform(long msgId, String jobType, String jobName) {
        if (iMsgDao.existsById(msgId)) {
            Msg msg = iMsgDao.findById(msgId).get();
            Toke toke = remoteSecurityService.getServerToken();
            messageService.pushMsg(toke.getToke(), toke.getProduct(), toke.getAppKey(), msg);
        }
        removeJob(jobName);
    }

}
