package com.cm.websocket.manager;

import com.alibaba.fastjson.JSONObject;
import com.cm.websocket.enums.AppSocketTypeEnum;
import com.cm.websocket.exception.AppSessionException;
import com.cm.websocket.exception.SessionException;
import com.cm.websocket.exception.UserSessionException;
import com.cm.websocket.pojo.AppSocketMessage;
import com.cm.websocket.pojo.AppSocketSession;
import com.cm.websocket.service.IMessageService;
import org.apache.commons.lang3.StringUtils;

import javax.websocket.Session;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: WebSocketSessionManager
 * @Description: websocket会话管理
 * @Author: WangGeng
 * @Date: 2020/9/26 11:41
 * @Version: 1.0
 **/
public class AppSocketSessionManager {
    public static final String FORM_SYSTEM = "SYSTEM";

    private static AppSocketSessionManager appSocketSessionManager = ManagerBuilder.APP_SOCKET_SESSION_MANAGER;
    private Map<String, AppSocketSession> sessionMap = new ConcurrentHashMap<>(1000);
    private IMessageService messageService;

    private AppSocketSessionManager() {
    }

    public static AppSocketSessionManager getInstance() {
        return appSocketSessionManager;
    }

    public void addSession(Session session) {
        AppSocketSession appSocketSession = new AppSocketSession();
        appSocketSession.setSession(session);
        sessionMap.put(session.getId(), appSocketSession);
    }

    public void registerAppWebSocket(String sessionId, AppSocketMessage.RegisterBody registerBody) throws SessionException {
        AppSocketSession appSocketSession = getSessionById(sessionId);
        appSocketSession.setAppId(registerBody.getAppId());
        appSocketSession.setUserId(registerBody.getUserId());
    }

    public AppSocketSession getSessionById(String sessionId) throws SessionException {
        AppSocketSession appSocketSession = sessionMap.get(sessionId);
        if (appSocketSession == null) {
            throw new SessionException("Session invalid，sessionId" + sessionId);
        }
        return appSocketSession;
    }

    public AppSocketSession getSessionByUserId(String userId) throws UserSessionException {
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketSession appSocketSession = kv.getValue();
            if (StringUtils.equals(appSocketSession.getUserId(), userId)) {
                return appSocketSession;
            }
        }
        throw new UserSessionException("User no session, userId: " + userId);
    }

    public List<AppSocketSession> listSessionByUserId(String userId) throws UserSessionException {
        List<AppSocketSession> appSocketSessions = new ArrayList<>();
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketSession appSocketSession = kv.getValue();
            if (StringUtils.equals(appSocketSession.getUserId(), userId)) {
                appSocketSessions.add(appSocketSession);
            }
        }
        return appSocketSessions;
    }

    public AppSocketSession getSessionByAppId(String appId) throws AppSessionException {
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketSession appSocketSession = kv.getValue();
            if (StringUtils.equals(appSocketSession.getAppId(), appId)) {
                return appSocketSession;
            }
        }
        throw new AppSessionException("App no session, appId: " + appId);
    }

    /**
     * 会话列表
     *
     * @return
     */
    public List<AppSocketSession> listSession() {
        List<AppSocketSession> appSocketSessions = new ArrayList<>();
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            appSocketSessions.add(kv.getValue());
        }
        return appSocketSessions;
    }

    /**
     * 会话列表
     *
     * @param appIds appId列表
     * @return
     */
    public List<AppSocketSession> listSessionByAppIds(List<String> appIds) {
        List<AppSocketSession> appSocketSessions = new ArrayList<>();
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketSession appSocketSession = kv.getValue();
            for (String appId : appIds) {
                if (StringUtils.equals(appSocketSession.getAppId(), appId)) {
                    appSocketSessions.add(appSocketSession);
                }
            }
        }
        return appSocketSessions;
    }

    /**
     * 会话列表
     *
     * @param userIds userId列表
     * @return
     */
    public List<AppSocketSession> listSessionByUserIds(List<String> userIds) {
        List<AppSocketSession> appSocketSessions = new ArrayList<>();
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketSession appSocketSession = kv.getValue();
            for (String userId : userIds) {
                if (StringUtils.equals(appSocketSession.getUserId(), userId)) {
                    appSocketSessions.add(appSocketSession);
                }
            }
        }
        return appSocketSessions;
    }

    /**
     * 群发文本消息
     *
     * @param message
     * @return
     */
    public int sendTextMessage(String message) {
        int total = 0;
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketMessage appSocketMessage = new AppSocketMessage(AppSocketTypeEnum.SYSTEM_GROUP_MESSAGE.getValue(), true, FORM_SYSTEM, kv.getValue().getAppId(), message);
            sendText(kv.getValue().getSession(), appSocketMessage);
            total++;
        }
        return total;
    }

    /**
     * 群发文本消息
     *
     * @param appIds  appId列表
     * @param message
     * @return
     */
    public int sendTextMessageByAppIds(List<String> appIds, String message) {
        int total = 0;
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketSession appSocketSession = kv.getValue();
            for (String appId : appIds) {
                if (StringUtils.equals(appSocketSession.getAppId(), appId)) {
                    AppSocketMessage appSocketMessage = new AppSocketMessage(AppSocketTypeEnum.SYSTEM_GROUP_MESSAGE.getValue(), true, FORM_SYSTEM, appId, message);
                    sendText(kv.getValue().getSession(), appSocketMessage);
                    total++;
                }
            }
        }
        return total;
    }

    /**
     * 群发文本消息
     *
     * @param userIds userId列表
     * @param message
     * @return
     */
    public int sendTextMessageByUserIds(List<String> userIds, String message) {
        int total = 0;
        for (Map.Entry<String, AppSocketSession> kv : sessionMap.entrySet()) {
            AppSocketSession appSocketSession = kv.getValue();
            for (String userId : userIds) {
                if (StringUtils.equals(appSocketSession.getUserId(), userId)) {
                    AppSocketMessage appSocketMessage = new AppSocketMessage(AppSocketTypeEnum.SYSTEM_GROUP_MESSAGE.getValue(), true, FORM_SYSTEM, appSocketSession.getAppId(), message);
                    sendText(kv.getValue().getSession(), appSocketMessage);
                    total++;
                }
            }
        }
        return total;
    }

    private void sendText(Session session, AppSocketMessage appSocketMessage) {
        session.getAsyncRemote().sendText(JSONObject.toJSONString(appSocketMessage));
    }

    public void removeSessionById(String sessionId) {
        sessionMap.remove(sessionId);
    }

    private static class ManagerBuilder {
        public static final AppSocketSessionManager APP_SOCKET_SESSION_MANAGER = new AppSocketSessionManager();
    }

    public IMessageService getMessageService() {
        return messageService;
    }

    public void setMessageService(IMessageService messageService) {
        this.messageService = messageService;
    }
}
