package com.webchat.controller.client;

import com.webchat.common.enums.RedisMessageChannelTopicEnum;
import com.webchat.common.util.JsonUtil;
import com.webchat.common.util.SpringContextUtil;
import com.webchat.domain.vo.request.mess.VideoChatMessageRequestVO;
import com.webchat.domain.vo.response.UserBaseResponseInfoVO;
import com.webchat.service.listener.RedisMessageSender;
import io.swagger.annotations.Api;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Component;

import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Api(tags = "【音视频】分布式群聊信令服务")
@Data
@Slf4j
@Component
@ServerEndpoint(value = "/ws/group-video-chat/dcs/{groupId}/{userId}")
public class GroupVideoChatDcsWebSocket {
    /**
     * 群聊多人音视频webscoket连接对象存储
     */
    public static ConcurrentHashMap<String, LinkedHashMap<String, GroupVideoChatDcsWebSocket>> clients = new ConcurrentHashMap();
    //每个连接都会有自己的会话
    private Session session;
    private String groupId;
    private String userId;

    @OnOpen
    public void open(@PathParam("groupId") String groupId, @PathParam("userId") String userId, Session session, EndpointConfig config){
        log.info("音视频通话用户{}的客户端连接成功！", userId);
        LinkedHashMap<String, GroupVideoChatDcsWebSocket> userSocketTable = clients.get(groupId);
        if (userSocketTable == null) {
            userSocketTable = new LinkedHashMap<>();
            clients.put(groupId, userSocketTable);
        }
        userSocketTable.put(userId, this);
        this.session = session;
        this.groupId = groupId;
        this.userId = userId;
        // 同步当前在线群聊
        RedisMessageSender redisMessageSender = SpringContextUtil.getBean(RedisMessageSender.class);
        VideoCustomMessage videoCustomMessage = new VideoCustomMessage();
        videoCustomMessage.setType("online");
        videoCustomMessage.setGroupId(groupId);
        videoCustomMessage.setUserIds(getOnlineUserIdList(groupId));
        redisMessageSender.sendMessage(RedisMessageChannelTopicEnum.GROUP_VIDEO_ONLINE.getChannel(), JsonUtil.toJsonString(videoCustomMessage));
    }

    @OnClose
    public void close(){
        Map<String, GroupVideoChatDcsWebSocket> userClients = clients.get(groupId);
        if (MapUtils.isNotEmpty(userClients)) {
            userClients.remove(userId);
        }
    }

    @OnError
    public void error(Throwable error){
        error.printStackTrace();
    }

    @OnMessage
    public void onMessage(String message) {
        log.info("收到来自用户{}的消息:{}", userId, message);
        VideoChatMessageRequestVO chatMessage = JsonUtil.fromJson(message, VideoChatMessageRequestVO.class);
        if (chatMessage == null) {
            return;
        }
        RedisMessageSender redisMessageSender = SpringContextUtil.getBean(RedisMessageSender.class);
        if (chatMessage.getType().equals("call")) {
            // 发送通过邀请提醒消息
            // 支持分布式场景，走广播模式
            redisMessageSender.sendMessage(RedisMessageChannelTopicEnum.GROUP_VIDEO_OFFER_SEND.getChannel(), message);
            return;
        }
        if (chatMessage.getType().equals("offer")) {
            // 发送对话数据
            redisMessageSender.sendMessage(RedisMessageChannelTopicEnum.GROUP_VIDEO_OFFER_SEND.getChannel(), message);
            return;
        }
        // 发送对话数据
        redisMessageSender.sendMessage(RedisMessageChannelTopicEnum.GROUP_VIDEO_OFFER_SEND.getChannel(), message);
    }

    @Data
    public static class VideoCustomMessage {
        private String type;
        private String groupId;
        private Set<String> userIds;
        private List<UserBaseResponseInfoVO> onlineUsers;
    }

    private Set<String> getOnlineUserIdList(String groupId) {
        LinkedHashMap<String, GroupVideoChatDcsWebSocket> userClients = this.clients.get(groupId);
        if (MapUtils.isEmpty(userClients)) {
            return Collections.emptySet();
        }
        return userClients.keySet();
    }
}

