package com.doodl6.springmvc.web.controller;

import com.doodl6.springmvc.web.response.base.BaseResponse;
import com.doodl6.springmvc.web.vo.MessageVo;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Queues;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 聊天控制类,基于异步请求实现
 * Created by daixiaoming on 2018-12-10.
 */
@RestController
@RequestMapping("/chat")
public class ChatController extends BaseController {

    /**
     * 用户ID生成器
     */
    private static final AtomicInteger USER_ID_GENERATOR = new AtomicInteger();

    private static final Map<Integer, String> USER_MAP = Maps.newHashMap();

    /**
     * 为每个用户维护一份聊天记录队列
     */
    private static final Map<Integer, LinkedBlockingDeque<MessageVo>> MESSAGE_QUEUE_MAP = Maps.newHashMap();

    /**
     * 拉取数据,如果没有数据,会hold一段时间
     */
    @RequestMapping("/pullData")
    public DeferredResult<BaseResponse<List<MessageVo>>> pullData(Integer userId) {

        Preconditions.checkArgument(userId != null, "用户ID不能为空");

        Preconditions.checkArgument(USER_MAP.containsKey(userId), "用户不在聊天室内");

        //超时5秒钟
        DeferredResult<BaseResponse<List<MessageVo>>> deferredResult = new DeferredResult<>(5000L, new BaseResponse<>());

        PullDataThread pullDataThread = new PullDataThread(userId, deferredResult, 4000);
        ForkJoinPool.commonPool().submit(pullDataThread);

        return deferredResult;
    }

    /**
     * 进入聊天室
     */
    @RequestMapping("/intoChatRoom")
    public BaseResponse<Integer> intoChatRoom(String userName) {

        Preconditions.checkArgument(StringUtils.isNotEmpty(userName), "用户名不能为空");

        int userId = USER_ID_GENERATOR.incrementAndGet();

        MESSAGE_QUEUE_MAP.put(userId, Queues.newLinkedBlockingDeque());

        USER_MAP.put(userId, userName + "[" + userId + "]");

        BaseResponse<Integer> response = new BaseResponse<>();
        response.setData(userId);
        return response;
    }

    /**
     * 发送聊天信息
     */
    @RequestMapping("/sendMessage")
    public BaseResponse<Void> sendMessage(Integer userId, String content) {
        Preconditions.checkArgument(userId != null, "用户ID不能为空");
        Preconditions.checkArgument(StringUtils.isNotBlank(content), "消息内容不能为空");
        Preconditions.checkArgument(USER_MAP.containsKey(userId), "用户不存在");

        String userName = USER_MAP.get(userId);

        MessageVo messageVo = new MessageVo();
        messageVo.setUserId(userId);
        messageVo.setUserName(userName);
        messageVo.setSendTime(new Date());
        messageVo.setContent(content);

        for (Integer id : USER_MAP.keySet()) {
            MESSAGE_QUEUE_MAP.get(id).add(messageVo);
        }

        return BaseResponse.success();
    }

    static class PullDataThread implements Runnable {

        /**
         * 用户ID
         */
        private final int userId;

        private final DeferredResult<BaseResponse<List<MessageVo>>> deferredResult;

        /**
         * 超时时间(单位:毫秒)
         */
        private final int timeout;

        PullDataThread(int userId, DeferredResult<BaseResponse<List<MessageVo>>> deferredResult, int timeout) {
            this.userId = userId;
            this.deferredResult = deferredResult;
            this.timeout = timeout;
        }

        @Override
        public void run() {
            LinkedBlockingDeque<MessageVo> messageQueue = MESSAGE_QUEUE_MAP.get(userId);
            BaseResponse<List<MessageVo>> response = new BaseResponse<>();
            List<MessageVo> list = Lists.newArrayList();

            MessageVo vo;
            try {
                if ((vo = messageQueue.poll(timeout, TimeUnit.MILLISECONDS)) != null) {
                    list.add(vo);
                    //一次最多取10条信息
                    for (int i = 0; i < 9; i++) {
                        vo = messageQueue.poll();
                        if (vo == null) {
                            break;
                        }
                        list.add(vo);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            response.setData(list);
            deferredResult.setResult(response);
        }
    }

}