package com.keao.edu.im.job;

import com.keao.edu.im.common.ApiException;
import com.keao.edu.im.common.ErrorEnum;
import com.keao.edu.im.config.RoomProperties;
import com.keao.edu.im.config.WhiteBoardProperties;
import com.keao.edu.im.mec.im.IMHelper;
import com.keao.edu.im.mec.im.message.TicketExpiredMessage;
import com.keao.edu.im.pojo.ScheduledTaskInfo;
import com.keao.edu.im.service.RoomService;
import com.keao.edu.im.dao.RoomDao;
import com.keao.edu.im.dao.RoomMemberDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by weiqinxiao on 2019/3/15.
 */
@Slf4j
@Service
public class ScheduleManager implements SchedulingConfigurer {
    private ScheduledTaskRegistrar taskRegistrar;

    @Autowired
    RoomProperties roomProperties;

    @Autowired
    WhiteBoardProperties whiteBoardProperties;

    @Autowired
    IMHelper imHelper;

    @Autowired
    RoomMemberDao roomMemberDao;

    @Autowired
    RoomDao roomDao;

    @Autowired
    RoomService roomService;

    private ConcurrentHashMap<String, ScheduledTask> schedulingTasks = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, ScheduledTask> roomCacheTasks = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, Date> userIMOfflineMap = new ConcurrentHashMap<>();
    private ScheduledDelayTask userIMOfflineKickTask = new ScheduledDelayTask(new Runnable() {
        @Override
        public void run() {
            for (Map.Entry<String, Date> entry : userIMOfflineMap.entrySet()) {
                long currentTimeMillis = System.currentTimeMillis();
                log.info("userIMOfflineKickTask entry={}, currentTimeMillis={}", entry.getValue().getTime(), currentTimeMillis);
                if (currentTimeMillis - entry.getValue().getTime() > roomProperties.getUserIMOfflineKickTtl()) {
                    userIMOfflineMap.remove(entry.getKey());
                    roomService.userIMOfflineKick(entry.getKey());
                }
            }
        }
    }, 60000, 60000, null);

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.scheduleFixedDelayTask(userIMOfflineKickTask);
        this.taskRegistrar = scheduledTaskRegistrar;
        log.info("config schedule: taskTtl = {}, roomTtl={}, roomMaxCount={}, ", roomProperties.getTaskTtl(), roomProperties.getRoomTtl(), roomProperties.getMaxCount());
        log.info("config whiteboard: host={}", whiteBoardProperties.getHost());
    }

    public void userIMOffline(String userId) {
        userIMOfflineMap.put(userId, new Date());
    }

    public void userIMOnline(String userId) {
        userIMOfflineMap.remove(userId);
    }

    public void addExpiredTask(RoomService roomService, String roomId) {
        log.info("addExpiredTask destroyRoom: {}", roomId);
        ScheduledTask task = taskRegistrar.scheduleFixedDelayTask(new ScheduledDelayTask(new Runnable() {
            @Override
            public void run() {
                ScheduledTask task = roomCacheTasks.remove(roomId);
                roomService.destroyRoom(roomId);
                task.cancel();
            }
        }, roomProperties.getRoomTtl() * 10, roomProperties.getRoomTtl(), null));
        roomCacheTasks.put(roomId, task);
    }

    public void addTask(ScheduledTaskInfo task) {
        log.info("add speech task: {}", task);
        schedulingTasks.put(task.getTicket(), taskRegistrar.scheduleFixedDelayTask(new ScheduledDelayTask(new Runnable() {
            @Override
            public void run() {
                log.info("speech task expired, execute task: {}", task);
                TicketExpiredMessage msg = new TicketExpiredMessage();
                msg.setFromUserId(task.getApplyUserId());
                msg.setToUserId(task.getTargetUserId());
                msg.setTicket(task.getTicket());
                try {
                    imHelper.publishMessage(task.getTargetUserId(), task.getRoomId(), msg);
                } catch (Exception e) {
                    log.error("msg send error: {}", e.getMessage());
                }
                ScheduledTask scheduledTask = schedulingTasks.remove(task.getTicket());
                scheduledTask.cancel();
            }
        }, roomProperties.getTaskTtl() * 60, roomProperties.getTaskTtl(), task)));
    }

    public ScheduledTaskInfo executeTask(String key) {
        ScheduledTask scheduledTask = schedulingTasks.remove(key);
        if (scheduledTask == null) {
            log.error("task not exist: key={}", key);
            throw new ApiException(ErrorEnum.ERR_APPLY_TICKET_INVALID);
        }
        ScheduledDelayTask task = (ScheduledDelayTask)scheduledTask.getTask();
        ScheduledTaskInfo taskInfo = task.getScheduledTaskInfo();
        scheduledTask.cancel();
        log.info("execute speech task: {}", taskInfo);
        return taskInfo;
    }
}
