package com.itheima.message.websocket;

import com.alibaba.fastjson.JSON;
import com.itheima.util.Beans;
import com.itheima.util.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

/*****
 * @Author: http://www.itheima.com
 * @Description: com.itheima.message.websocket.WebSocketServer
 ****/
@Slf4j
@ServerEndpoint(value = "/listener/{key}")
@Component
public class WebSocketServer{

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private static Map<String,Session> sessions=new HashMap<String,Session>();

    /**
     * 连接建立成功调用的方法
     * */
    @OnOpen
    public void onOpen(@PathParam("key") String key, Session session) {
        //RedisTemplate
        RedisTemplate redisTemplate = Beans.getBean("redisTemplate");
        //获取Session.id
        String id = Beans.unique + session.getId();
        //获取用户会话信息
        String oldId = (String) redisTemplate.boundHashOps(Constant.MESSAGELIST).get(key);

        //非空
        if(!StringUtils.isEmpty(oldId)){
            //移除会话
            sessions.remove(id);
        }

        //建立会话
        sessions.put(id,session);
        //会话映射关系保存到Redis
        redisTemplate.boundHashOps(Constant.MESSAGELIST).put(key,id);
        redisTemplate.boundHashOps(Constant.IDMESSAGELIST).put(id,key);
        try {
            sendMessage(message("连接成功！",200,200));
            //获取历史消息
            Object moneyInfo = redisTemplate.boundListOps(Constant.OLDMESSAGELIST + key).rightPop();
            while (!StringUtils.isEmpty(moneyInfo)){
                Map<String,Object> moneyMap = JSON.parseObject(moneyInfo.toString(),Map.class);
                if(Double.valueOf(moneyMap.get("money").toString())>0){
                    sendMessage(message("恭喜你，成功抢到红包！",key,200,moneyMap.get("money").toString(),201));
                }else{
                    sendMessage(message("来晚了，红包一抢而空！",key,204,moneyMap.get("money").toString(),201));
                }
                //设置消息为空
                moneyInfo=null;
            }
        } catch (IOException e) {
            log.error("websocket IO异常");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        //RedisTemplate
        RedisTemplate redisTemplate = Beans.getBean("redisTemplate");
        //唯一id
        String id = Beans.unique + session.getId();
        //移除会话
        sessions.remove(id);
        //移除Redis缓存映射数据
        String key = (String) redisTemplate.boundHashOps(Constant.IDMESSAGELIST).get(id);
        redisTemplate.boundHashOps(Constant.MESSAGELIST).delete(key);
        redisTemplate.boundHashOps(Constant.IDMESSAGELIST).delete(id);
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * */
    @OnMessage
    public void onMessage(String message) {
        log.info("来自客户端的消息:" + message);
        //群发消息
        for (Map.Entry<String, Session> sessionEntry : sessions.entrySet()) {
            try {
                sessionEntry.getValue().getBasicRemote().sendText("收到您发送的消息："+message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发生异常处理方法
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /***
     * 群发
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
        for (Map.Entry<String, Session> sessionEntry : sessions.entrySet()) {
            sessionEntry.getValue().getBasicRemote().sendText(message);
        }
    }

    /***
     * 给指定用户发送消息
     * @param message
     * @param key
     * @throws IOException
     */
    public void sendMessage(String message,String key) throws IOException {
        //RedisTemplate
        RedisTemplate redisTemplate = Beans.getBean("redisTemplate");
        //移除Redis缓存映射数据
        String id = (String) redisTemplate.boundHashOps(Constant.MESSAGELIST).get(key);
        //获取会话
        Session session = sessions.get(id);
        if(session!=null){
            //发送消息
            session.getBasicRemote().sendText(message);
        }else{
            //消息缓存
            redisTemplate.boundListOps(Constant.OLDMESSAGELIST+key).leftPush(message);
        }
    }

    /**
     * 群发自定义消息
     * */
    public void sendAllMessage(String message) throws IOException {
        sendMessage(message);
    }


    /***
     * 消息转换
     * @param message
     * @param user
     * @param code
     * @return
     */
    public static String message(String message,String user,Integer code,String money,Integer status){
        Map<String,Object> messageMap = new HashMap<String,Object>();
        messageMap.put("message",message);
        messageMap.put("user",user);
        messageMap.put("type","message");
        messageMap.put("code",code);
        messageMap.put("money",money);
        messageMap.put("status",status);
        return JSON.toJSONString(messageMap);
    }

    //提示信息
    public static String message(String message,Integer code,Integer status){
        Map<String,Object> messageMap = new HashMap<String,Object>();
        messageMap.put("message",message);
        messageMap.put("type","message");
        messageMap.put("code",code);
        messageMap.put("status",status);
        return JSON.toJSONString(messageMap);
    }
}