package cn.com.ty.lift.ud.chat.controller;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import cn.com.ty.lift.ud.chat.controller.model.User;
import cn.com.ty.lift.ud.utils.ApplicationContextUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import cn.com.ty.lift.ud.chat.mapper.entity.ChatMsgEntity;
import cn.com.ty.lift.ud.chat.mapper.entity.ChatSessionEntity;
import cn.com.ty.lift.ud.chat.service.impl.ChatMsgServiceImpl;
import cn.com.ty.lift.ud.chat.service.impl.ChatSessionServiceImpl;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;

@Api(tags = "聊天记录 API - 盛文静")
@ServerEndpoint(value = "/websocket")
@Component
@Deprecated
public class MyWebSocket {

    private static final Logger logger = LoggerFactory.getLogger(MyWebSocket.class);

    // 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    // 与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    // 用以记录用户和房间号的对应关系(sessionId,room)
    private static HashMap<String, String> RoomForUser = new HashMap<String, String>();

    // 用以记录房间和其中用户群的对应关系(room,List<用户>)
    public static HashMap<String, CopyOnWriteArraySet<User>> UserForRoom =
        new HashMap<String, CopyOnWriteArraySet<User>>();

    // 用以记录房间和其中用户群的对应关系(room,List<用户>)
    public static HashMap<String, String> PwdForRoom = new HashMap<String, String>();

    private Gson gson = new Gson();

    /**
     * 连接建立成功调用的方法
     * 
     * @param session
     */
    @OnOpen
    public void onOpen(Session session) throws IOException {
        logger.debug("---------------------成功与{}建立连接---------------------", session.getId());
        this.session = session;
        addOnlineCount();
        Map<String, String> result = new HashMap<>();
        result.put("type", "bing");
        result.put("sendUser", "系统消息");
        result.put("id", session.getId());
        this.sendMessage(gson.toJson(result));
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        subOnlineCount();
        CopyOnWriteArraySet<User> users = getUsers(session);
        if (users != null) {
            String nick = "有人";
            for (User user : users) {
                if (user.getId().equals(session.getId())) {
                    nick = user.getNickname();
                }
            }
            Map<String, String> result = new HashMap<>();
            result.put("type", "init");
            result.put("msg", nick + "离开房间");
            result.put("sendUser", "系统消息");
            sendMessagesOther(users, gson.toJson(result));
            User closeUser = getUser(session);
            users.remove(closeUser);
            if (users.size() == 0) {
                String room = RoomForUser.get(session.getId());
                UserForRoom.remove(room);
                PwdForRoom.remove(room);
            }
            RoomForUser.remove(session.getId());
        }
    }

    /**
     * 收到客户端消息后调用的方法
     * 
     * @param message
     *            消息内容
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        Map<String, String> map = new Gson().fromJson(message, new TypeToken<HashMap<String, String>>() {}.getType());
        Map<String, Object> result = new HashMap<>();
        User user = null;
        String shiels = map.containsKey("shiels") ? map.get("shiels").toString() : null;
        switch (map.get("type")) {
            case "msg":
                user = getUser(session);
                result.put("type", "msg");
                result.put("msg", map.get("msg"));
                result.put("sendUser", user.getNickname());
                result.put("shake", map.get("shake"));
                result.put("id", user.getId());
                break;
            case "init":
                String room = map.get("room");
                String nick = "";
                String pwd = map.get("pwd");
                if (room != null) {

                    // 拿到房间号判断是否有效
                    ChatSessionServiceImpl sessionService =
                        ApplicationContextUtil.getBean(ChatSessionServiceImpl.class);
                    ChatSessionEntity sessionDb = sessionService.findOneBySessionIdAndPwd(room, pwd);
                    if (null == sessionDb) {
                        logger.debug("房间信息有误！");
                        nick = map.get("nick");
                    } else {
                        nick = sessionDb.getUserName();
                    }
                    user = new User(sessionDb, session.getId(), room, nick, this);
                    // 如果房间不存在，新建房间
                    if (UserForRoom.get(room) == null) {
                        CopyOnWriteArraySet<User> roomUsers = new CopyOnWriteArraySet<>();
                        roomUsers.add(user);
                        UserForRoom.put(room, roomUsers);
                        if (StrUtil.isNotEmpty(pwd)) {
                            PwdForRoom.put(room, pwd);
                        }
                        RoomForUser.put(session.getId(), room);
                    } else {
                        UserForRoom.get(room).add(user);
                        RoomForUser.put(session.getId(), room);
                    }
                    result.put("type", "init");
                    result.put("msg", nick + "成功加入房间");
                    result.put("sendUser", "系统消息");
                    result.put("id", 0);
                }
                break;
            case "img":
                user = getUser(session);
                result.put("type", "img");
                result.put("msg", map.get("msg"));
                result.put("sendUser", user.getNickname());
                result.put("id", user.getId());
                break;
            case "video":
                user = getUser(session);
                result.put("type", "video");
                result.put("msg", map.get("msg"));
                result.put("sendUser", user.getNickname());
                result.put("id", user.getId());
                break;
            case "Voice":
                user = getUser(session);
                result.put("type", "Voice");
                result.put("msg", map.get("msg"));
                result.put("sendUser", user.getNickname());
                result.put("id", user.getId());
                break;
            case "ping":
                return;
        }
        if (StrUtil.isEmpty(shiels)) {
            sendMessagesOther(getUsers(session), gson.toJson(result));
        } else {
            sendMessagesOther(getUsers(session), gson.toJson(result), shiels);
        }
    }

    /**
     * 连接发生错误时的调用方法
     * 
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.debug("---------------------与{}的连接发生错误---------------------", session.getId());
        subOnlineCount();
        CopyOnWriteArraySet<User> users = getUsers(session);
        if (users != null) {
            String nick = "有人";
            for (User user : users) {
                if (user.getId().equals(session.getId())) {
                    nick = user.getNickname();
                }
            }
            Map<String, String> result = new HashMap<>();
            result.put("type", "init");
            result.put("msg", nick + "离开房间");
            result.put("sendUser", "系统消息");
            sendMessagesOther(users, gson.toJson(result));
            User closeUser = getUser(session);
            users.remove(closeUser);
            if (users.size() == 0) {
                String room = RoomForUser.get(session.getId());
                UserForRoom.remove(room);
                PwdForRoom.remove(room);
            }
            RoomForUser.remove(session.getId());
        }
        error.printStackTrace();
    }

    public void sendMessage(String message) throws IOException {
        Map<String, String> map = new Gson().fromJson(message, new TypeToken<HashMap<String, String>>() {}.getType());
        int sendUserId = 0;
        String room = RoomForUser.get(this.session.getId());
        switch (map.get("type")) {
            case "init":
                logger.debug("系统消息:{}", map.get("msg"));
                break;
            case "msg":
                logger.debug("{}成功发出了消息:{}", map.get("sendUser"), map.get("msg"));
                sendUserId = Integer.parseInt(map.get("id"));
                this.saveMsg(sendUserId, map.get("msg"), 1, 1, room);
                break;
            case "img":
                logger.debug("{}成功发送了一张图片:{}", map.get("sendUser"), map.get("msg"));
                sendUserId = Integer.parseInt(map.get("id"));
                this.saveMsg(sendUserId, map.get("msg"), 1, 2, room);
                break;
            case "video":
                logger.debug("{}成功发送了视频:{}", map.get("sendUser"), map.get("msg"));
                sendUserId = Integer.parseInt(map.get("id"));
                this.saveMsg(sendUserId, map.get("msg"), 1, 3, room);
                break;
            case "Voice":
                logger.debug("{}成功发送了语音:{}", map.get("sendUser"), map.get("msg"));
                sendUserId = Integer.parseInt(map.get("id"));
                this.saveMsg(sendUserId, map.get("msg"), 1, 4, room);
                break;
            default:
                break;
        }

        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 保存消息记录
     * 
     * @param sendUserId
     *            发送人id
     * @param msg
     *            文本信息
     * @param status
     *            状态 0:正常1:屏蔽
     * @param type
     *            消息类型：1文本、2图片、3视频、4语音'
     * @param sessionid
     *            房间号号'
     */
    private void saveMsg(Integer sendUserId, String msg, Integer status, Integer type, String sessionid) {
        ChatMsgEntity entity = new ChatMsgEntity();
        entity.setMsg(msg);
        entity.setStatuz(status);
        entity.setSessionid(sessionid);
        entity.setType(type);
        entity.setFromUser(sendUserId+"");
        ApplicationContextUtil.getBean(ChatMsgServiceImpl.class).save(entity);
    }

    /**
     * 获得在线人数
     * 
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        MyWebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        MyWebSocket.onlineCount--;
    }

    /**
     * 根据当前用户的session获得他所在房间的所有用户
     * 
     * @param session
     * @return
     */
    private CopyOnWriteArraySet<User> getUsers(Session session) {
        String room = RoomForUser.get(session.getId());
        CopyOnWriteArraySet<User> users = UserForRoom.get(room);
        return users;
    }

    private User getUser(Session session) {
        String room = RoomForUser.get(session.getId());
        CopyOnWriteArraySet<User> users = UserForRoom.get(room);
        if (null != users) {
            for (User user : users) {
                if (session.getId().equals(user.getId())) {
                    return user;
                }
            }
        }

        return null;
    }

    private User getUser(Integer session) {
        String room = RoomForUser.get(session);
        CopyOnWriteArraySet<User> users = UserForRoom.get(room);
        if (null != users) {
            for (User user : users) {
                if (session.equals(user.getId())) {
                    return user;
                }
            }
        }

        return null;
    }

    /**
     * 给某个房间的所有人发送消息
     * 
     * @param users
     * @param message
     */
    private void sendMessagesAll(CopyOnWriteArraySet<User> users, String message) {
        // 群发消息
        for (User item : users) {
            try {
                item.getWebSocket().sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 给某个房间除自己外发送消息
     * 
     * @param users
     * @param message
     */
    private void sendMessagesOther(CopyOnWriteArraySet<User> users, String message) {
        // 群发消息
        for (User item : users) {
            if (item.getWebSocket() != this) {
                try {
                    item.getWebSocket().sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 给某个房间除自己外发送消息
     * 
     * @param users
     * @param message
     */
    private void sendMessagesOther(CopyOnWriteArraySet<User> users, String message, String shiel) {
        List<String> shiels = Arrays.asList(shiel.split(","));
        // 群发消息
        for (User item : users) {
            if (item.getWebSocket() != this && !shiels.contains(item.getId())) {
                try {
                    item.getWebSocket().sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}