package com.sqx.modules.map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.sqx.common.utils.RedisUtils;
import com.sqx.common.utils.SpringContextUtils;
import com.sqx.ws.BaseInfoModel;
import com.sqx.ws.BaseModelEncoder;
import com.sqx.ws.HashMapEncoder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket聊天实现
 */
@Component
@Scope("prototype")
@ServerEndpoint(value = "/mapWebsocket/{businessId}", encoders = { HashMapEncoder.class, BaseModelEncoder.class })
public class MapWebSocket {
    private static final Logger log = LoggerFactory.getLogger(MapWebSocket.class);

    //通过类似GET请求方式传递参数的方法（服务端采用第二种方法"WebSocketHandler"实现）
    //websocket = new WebSocket("ws://127.0.0.1:18080/testWebsocket?id=23&name=Lebron");
    /**
     * 在线人数
     */
    public static int onlineNumber = 0;
    /**
     * 以用户的id为key，WebSocket为对象保存起来
     */
    private static final Map<String, MapWebSocket> clients = new ConcurrentHashMap<>();
    /**
     * 会话
     */
    private Session session;
    /**
     * 用户id
     */
    private String businessId;

    //此处不需要
//    //这里使用静态，让 service 属于类
//    private static ChatsContentService chatContentService;
//
//    //注入的时候，给类的 service 注入
//    @Autowired
//    public void setWxChatContentService(ChatsContentService chatContentService) {
//        MapWebSocket.chatContentService = chatContentService;
//    }

    private static RedisUtils redisUtils = SpringContextUtils.getBean(RedisUtils.class);

    @Autowired
    public void setRedisUtils(RedisUtils redisUtils) {
        MapWebSocket.redisUtils = redisUtils;
    }




    /**
     * 建立连接
     *
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("businessId") String businessId, Session session) {
        onlineNumber++;
        log.info("客户端连接Id: {}", businessId);
        this.businessId = businessId;
        this.session = session;
        log.info("有新连接加入！ 当前在线设备: {}", onlineNumber);
        try {
            //把自己的信息加入到map当中去
            clients.remove(businessId);
            clients.put(businessId, this);
            /*sendMessageTo("恭喜你连接成功！",wxUserId);*/
        } catch (Exception e) {
            log.info("{} 连接发生了错误", businessId);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.info("服务端发生了错误: {}", error.getMessage());
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose() {
        onlineNumber--;
        //webSockets.remove(this);
        clients.remove(businessId);
        log.info("有连接关闭！ 当前在线设备: {}", onlineNumber);
    }

    /**
     * 接收客户端的消息，并把消息发送给所有连接的会话
     */
    @OnMessage
    public void onMessage(String message) {
        try {
            log.info("客户端发来的消息：{}", message);
            //解析聊天内容
            JSONObject jsonObject = JSON.parseObject(message);
            String sendType = jsonObject.getString("sendType");
            String userId = jsonObject.getString("userId");
            String businessId = jsonObject.getString("businessId");
            String[] businessIds = StringUtils.split(businessId,",");
            switch (sendType){
                case "coordinate": {
                    //开始记录坐标值
                    String coordinate = jsonObject.getString("coordinate");
                    //往redis里存入坐标
                    //map:location:businessId:userId
                    for (String $businessId: businessIds){
                        //带，拆分
                        //redisUtils.set("map:location:" + $businessId +":" + userId, coordinate,-1);//60秒
                        redisUtils.set("map:location:" + $businessId +":" + userId, coordinate,60);//60秒
                    }
                    sendMessageObject(session,BaseInfoModel.success("coordinate","收到回执坐标信息是：" + coordinate + " businessId: " + businessId));//回执，告知已记录
                    break;
                }
                case "clearCoordinate": {
                    //结束动作，清空坐标
                    for (String $businessId: businessIds){
                        //带，拆分
                        redisUtils.delete("map:location:" + $businessId +":" + userId);
                    }

                    sendMessageObject(session,BaseInfoModel.success("clearCoordinate","ok"));//回执，告知已记录
                    break;
                }
                case "getCoordinate": {
                    //获取坐标
                    String rkey = jsonObject.getString("rkey");
                    log.info(rkey);
//                    String v = redisUtils.get(rkey);
                    Set<String> keys = redisUtils.keys(rkey);
                    Map<String,String> rmap = Maps.newHashMap();
                    for(String k: keys){
                        String v = redisUtils.get(k);
                        log.info(v);
                        String[] ks = StringUtils.split(k,":");
                        rmap.put(ks[ks.length-1],v);//返回用户ID-坐标的map
                    }
                    sendMessageObject(session,BaseInfoModel.success("getCoordinate",rmap));//回执，告知已记录
                    break;
                }
                default: {
                    log.info("默认无处理的客户端发来的坐标消息：{}", message);
                }
            }
        } catch (Exception e) {
            log.info("发生了错误了",e);
        }
    }

    /**
     * 发送消息，实践表明，每次浏览器刷新，session会发生变化。
     * @param session
     * @param message
     */
    public static void sendMessage(Session session, String message) throws IOException {
        try {
//          session.getBasicRemote().sendText(String.format("%s (From Server，Session ID=%s)",message,session.getId()));
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("发送消息出错：{}", e.getMessage());
            log.error(e.getMessage(),e);
        }
    }

    public static void sendMessageObject(Session session, Object message) throws IOException {
        try {
            session.getBasicRemote().sendObject(message);
        } catch (IOException | EncodeException e) {
            log.error("发送消息出错!");
            log.error(e.getMessage(),e);
        }
    }


    public static synchronized int getOnlineCount() {
        return onlineNumber;
    }

}
