package com.webchat.controller.client;

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.domain.vo.response.mess.ChatMessageResponseVO;
import com.webchat.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
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.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ServerEndpoint(value = "/ws/video-chat/{userId}")
public class VideoChatWebSocket {

    //存储客户端的连接对象,每个客户端连接都会产生一个连接对象
    private static ConcurrentHashMap<String, VideoChatWebSocket> map = new ConcurrentHashMap();

    //每个连接都会有自己的会话
    private Session session;

    private String userId;

    @OnOpen
    public void open(@PathParam("userId") String userId, Session session, EndpointConfig config){

        log.info("音视频通话用户{}的客户端连接成功！", userId);
        map.put(userId, this);
        this.session = session;
        this.userId = userId;
    }

    @OnClose
    public void close(){
        map.remove(userId);
    }

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

    @OnMessage
    public void onMessage(String message) throws IOException {

        log.info("收到来自用户{}的消息:{}", userId, message);

        VideoChatMessageRequestVO chatMessage = JsonUtil.fromJson(message, VideoChatMessageRequestVO.class);
        if (chatMessage == null) {
            return;
        }
        UserService userService = SpringContextUtil.getBean(UserService.class);
        String sendUserId = chatMessage.getUserId();
        String receiverId = chatMessage.getTargetUserId();
        UserBaseResponseInfoVO sender = userService.getUserInfoByUserId(sendUserId);
        UserBaseResponseInfoVO receiver = userService.getUserInfoByUserId(receiverId);
        if (sender.getRoleCode() > 2 || receiver.getRoleCode() > 2) {
            // 音视频当前仅支持普通用户之间对话
            return;
        }

        if (chatMessage.getType().equals("offer")) {
            // 视频对话发送offer，这里走的是普通聊天，推送音视频请求给接收人
            ChatMessageResponseVO chatMessageResponseVO = new ChatMessageResponseVO();
            chatMessageResponseVO.setVideoOffer(true);
            chatMessageResponseVO.setSenderId(sendUserId);
            chatMessageResponseVO.setReceiverId(receiverId);
            chatMessageResponseVO.setSenderName(sender.getUserName());
            String offerMessage = JsonUtil.toJsonString(chatMessageResponseVO);
            // 发送通过邀请提醒消息
            Session receiverSession = ChatWebSocket.clients.get(receiverId).getSession();
            receiverSession.getAsyncRemote().sendText(offerMessage);
            // offer
            Set<String> receiverUserIds = new HashSet<>();
            receiverUserIds.add(receiverId);
            sendMessageTo(message, receiverUserIds);
            return;
        }

        Set<String> receiverUserIds = new HashSet<>();
        receiverUserIds.add(receiverId);
        sendMessageTo(message, receiverUserIds);
    }

    public void sendMessageTo(String message, Set<String> receiver) throws IOException {
        if (CollectionUtils.isEmpty(receiver)) {
            return;
        }
        Set<Map.Entry<String, VideoChatWebSocket>> entries = map.entrySet();
        for (Map.Entry<String, VideoChatWebSocket> entry : entries) {
            if(receiver.contains(entry.getKey())){
                //将消息转发到其他非自身客户端
                entry.getValue().send(message);
            }
        }
    }

    public void send(String message) throws IOException {
        if(session.isOpen()){
            session.getBasicRemote().sendText(message);
        }
    }

    public int  getConnetNum(){
        return map.size();
    }
}

