package com.yeejoin.amos.boot.module.jcs.biz.service.impl;


import java.util.*;

import com.yeejoin.amos.boot.module.jcs.api.entity.ControllerLog;
import com.yeejoin.amos.boot.module.jcs.api.enums.ControllerTypeEnum;
import com.yeejoin.amos.boot.module.jcs.api.service.IControllerService;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.rdbms.service.BaseService;

import com.yeejoin.amos.boot.module.jcs.api.dto.ControllerDto;
import com.yeejoin.amos.boot.module.jcs.api.entity.Controller;
import com.yeejoin.amos.boot.module.jcs.api.mapper.ControllerMapper;

/**
 * <pre>
 * 联动控制器 服务实现类
 * </pre>
 *
 * @author gwb
 * @version $Id: ControllerServiceImpl.java, v 0.1 2021年8月20日 上午10:15:49 gwb Exp $
 */
@Service
public class ControllerServiceImpl extends BaseService<ControllerDto, Controller, ControllerMapper> implements IControllerService {
    /**
     * 将延迟的任务存放在Hashtable中，以便在多个请求中控制任务的取消分享等操作
     */
    private final Map<Long, TimerTask> tasks = new Hashtable<>();
    private final Timer timer = new Timer();
    public static final String CONTROLLER_STATE_CHANGED_TOPIC = "controllerStateChanged";

    @Autowired
    ControllerMapper controllerMapper;

    @Autowired
    ControllerEquipServiceImpl controllerEquipServiceImpl;

    @Autowired
    ControllerLogServiceImpl controllerLogServiceImpl;

    @Autowired
    private EmqKeeper emqKeeper;


    public List<ControllerDto> queryAllForList() {
        return this.queryForList("", false);
    }

    public List<ControllerDto> queryForList(String station, String type) {
        return this.queryForList("", false, station, type);
    }

    public List<ControllerDto> getCurrentStationController(Long sequenceNbr) {
        return controllerMapper.getCurrentStationController(sequenceNbr);
    }

    /**
     * 更新station联动控制器状态
     * 3.1.3  警铃、广播、车库门 联动规则：
     * 当 点击【全部启动】、【某大队全部启动】时：
     * 1>  首先：消防警铃第一时间  响铃持续15s 后自动关闭。
     * 2>  然后：警铃 响铃结束后，广播系统开启。广播 启动预制的 广播音频， 播放。
     * 3>  车库门和警铃第一时间自动开启。
     * 4>  系统 需要打印出 “警铃、广播、车库门 ” 启动指令和  停止指令的 日志。
     * 当同时 点击【启动警铃】、【启动广播】时
     * 1>  首先：消防警铃第一时间  响铃持续15s 后自动关闭。
     * 2>  然后：警铃 响铃结束后，广播系统开启。广播 启动预制的 广播音频， 播放。
     */
    public boolean changeControllerState(Controller[] controllers) {
        boolean isBatch = controllers.length > 1;
        if (isBatch) {//全部操作
            //分组
            HashSet<String> groupTypes = new HashSet<>();
            for (Controller controller : controllers) {
                groupTypes.add(controller.getStation());
            }
            //按分组进行归类
            List<Map<String, Controller>> groups = new ArrayList<>();
            groupTypes.forEach(groupType -> {
                Map<String, Controller> group = new HashMap<>();
                for (Controller controller : controllers) {
                    if (groupType.equals(controller.getStation())) group.put(controller.getType(), controller);
                }
                groups.add(group);
            });
            //开始处理
            startJob(groups);
        } else {//单个操作
            for (Controller controller : controllers) {
                //保存日志
                saveLog(controller);
                String type = controller.getType();
                // 打开警铃，并开始计时15秒，若15秒内启动广播，则播放完警铃后再播放广播
                if ("0".equals(controller.getState())) {//关闭操作
                    if (ControllerTypeEnum.BELL.getCode().equals(type)) {
                        //取消该警铃的任务
                        TimerTask stopBellTaskHistory = tasks.get(controller.getSequenceNbr());
                        if (stopBellTaskHistory != null) {
                            stopBellTaskHistory.cancel();
                            tasks.remove(controller.getSequenceNbr());
                        }
                        controllerEquipServiceImpl.changeBell(controller, "0");//关闭警铃
                    } else if (ControllerTypeEnum.BROADCAST.getCode().equals(type)) {
                        //取消该广播的任务
                        TimerTask startBroadcastTaskHistory = tasks.get(controller.getSequenceNbr());
                        if (startBroadcastTaskHistory != null) {
                            startBroadcastTaskHistory.cancel();
                            tasks.remove(controller.getSequenceNbr());
                        }
                        controllerEquipServiceImpl.changeBroadcast(controller, "0");//关闭广播
                    } else if (ControllerTypeEnum.DOOR.getCode().equals(type)) {//车库门不能关闭
                    }
                } else {//启动操作
                    if (ControllerTypeEnum.BELL.getCode().equals(type)) {//启动警铃
                        controllerEquipServiceImpl.changeBell(controller, "1");//启动警铃
                        //开始计时15秒,15秒后关闭警铃
                        TimerTask timerTask = new TimerTask() {
                            @Override
                            public void run() {
                                tasks.remove(controller.getSequenceNbr());
                                controllerEquipServiceImpl.changeBell(controller, "0");//关闭警铃
                            }
                        };
                        tasks.put(controller.getSequenceNbr(), timerTask);
                        timer.schedule(timerTask, 15000);
                    } else if (ControllerTypeEnum.BROADCAST.getCode().equals(type)) {//启动广播
                        controllerEquipServiceImpl.changeBroadcast(controller, "1");//开启广播
                    } else if (ControllerTypeEnum.DOOR.getCode().equals(type)) {//启动车库门
                        controllerEquipServiceImpl.changeDoor(controller, "1");//开启车库门
                    }
                }
            }
        }
        return true;
    }

    /**
     * 全部操作：启动警铃,启动车库门，15秒后关闭警铃，启动广播
     */
    public void startJob(List<Map<String, Controller>> groups) {
        groups.forEach(group -> {
            Controller bellController = group.get(ControllerTypeEnum.BELL.getCode());
            Controller broadcastController = group.get(ControllerTypeEnum.BROADCAST.getCode());
            Controller doorController = group.get(ControllerTypeEnum.DOOR.getCode());
            //保存操作日志
            saveLog(bellController);
            saveLog(broadcastController);
            saveLog(doorController);
            if ("0".equals(bellController.getState())) {//全部关闭(车库们不能关闭)
                //先查看是否有未执行的历史任务，如果有则取消任务
                TimerTask stopBellTaskHistory = tasks.get(bellController.getSequenceNbr());
                if (stopBellTaskHistory != null) {
                    stopBellTaskHistory.cancel();
                    tasks.remove(bellController.getSequenceNbr());
                }
                if (broadcastController != null) {
                    TimerTask startBroadcastTaskHistory = tasks.get(broadcastController.getSequenceNbr());
                    if (startBroadcastTaskHistory != null) {
                        startBroadcastTaskHistory.cancel();
                        tasks.remove(broadcastController.getSequenceNbr());
                    }
                }
                controllerEquipServiceImpl.changeBell(bellController, "0");//关闭警铃
                controllerEquipServiceImpl.changeBroadcast(broadcastController, "0");//关闭广播
            } else {//全部打开
                //立即启动警铃，打开车库门
                controllerEquipServiceImpl.changeBell(bellController, "1");//开启警铃
                controllerEquipServiceImpl.changeDoor(doorController, "1");//开启车库门
                //15秒后关闭警铃，启动广播
                TimerTask stopBellTask = new TimerTask() {
                    @Override
                    public void run() {
                        tasks.remove(bellController.getSequenceNbr());
                        controllerEquipServiceImpl.changeBell(bellController, "0");//关闭警铃
                    }
                };
                TimerTask startBroadcastTask = new TimerTask() {
                    @Override
                    public void run() {
                        tasks.remove(broadcastController.getSequenceNbr());
                        controllerEquipServiceImpl.changeBell(broadcastController, "1");//开启广播
                    }
                };
                //先查看是否有未执行的历史任务，如果有则取消任务
                TimerTask stopBellTaskHistory = tasks.get(bellController.getSequenceNbr());
                if (stopBellTaskHistory != null) stopBellTaskHistory.cancel();
                TimerTask startBroadcastTaskHistory = tasks.get(broadcastController.getSequenceNbr());
                if (startBroadcastTaskHistory != null) startBroadcastTaskHistory.cancel();
                //保存新的任务至map中，同时开始调度新任务
                tasks.put(bellController.getSequenceNbr(), stopBellTask);
                tasks.put(broadcastController.getSequenceNbr(), startBroadcastTask);
                timer.schedule(stopBellTask, 15000);
                timer.schedule(startBroadcastTask, 16000);
            }
        });
    }

    /**
     * 保存操作日志
     */
    private void saveLog(Controller controller) {
        if (controller == null) return;
        boolean update = updateById(controller);
        if (update) {
            ControllerLog controllerLog = new ControllerLog();
            controllerLog.setControllerSeq(controller.getSequenceNbr());
            controllerLog.setState(controller.getState());
            controllerLog.setExecuteDate(new Date());
            controllerLogServiceImpl.save(controllerLog);
        }
        // 分发状态变更通知
        try {
            emqKeeper.getMqttClient().publish(CONTROLLER_STATE_CHANGED_TOPIC, "".getBytes(), 2, true);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }
}
