package cn.reghao.tnb.message.app.ws.chat;

import cn.reghao.jutil.jdk.serializer.JdkSerializer;
import cn.reghao.jutil.jdk.serializer.JsonConverter;
import cn.reghao.tnb.message.api.model.EventType;
import cn.reghao.tnb.message.app.ws.chat.msg.EventReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.io.IOException;

/**
 * @author reghao
 * @date 2022-03-11 16:45:52
 */
@Slf4j
@Component
public class ChatHandler implements WebSocketHandler {
    private final ChatConnection chatConnection;
    private final ChatService chatService;

    public ChatHandler(ChatConnection chatConnection, ChatService chatService) {
        this.chatConnection = chatConnection;
        this.chatService = chatService;
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws IOException {
        boolean ret = chatConnection.addSession(webSocketSession);
        if (ret) {
            log.info("WebSocket 建立连接");
            chatConnection.sendPingPayload(webSocketSession);
            Long userId = chatConnection.getUserId(webSocketSession.getId());
            chatService.onLoginEvent(userId, true);
        } else {
            log.info("没有认证信息, 关闭 WebSocket 连接");
            webSocketSession.close(CloseStatus.NO_STATUS_CODE);
        }
    }

    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage)
            throws IOException {
        if (webSocketMessage instanceof TextMessage) {
            dispatchTextMessage(webSocketSession, (TextMessage) webSocketMessage);
        } else if (webSocketMessage instanceof BinaryMessage) {
            log.info("接收到 WebSocket 二进制消息");
            BinaryMessage binaryMessage = (BinaryMessage) webSocketMessage;
            Object object = JdkSerializer.deserialize(binaryMessage.getPayload().array());
        } else if (webSocketMessage instanceof PingMessage) {
            log.info("接收到 WebSocket PingMessage");
        } else if (webSocketMessage instanceof PongMessage) {
            log.info("接收到 WebSocket PongMessage");
        } else {
            log.error("接收到未知类型的 WebSocket 消息");
        }
    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) {
        log.error("WebSocket 数据传输错误");
        handleOnClose(webSocketSession);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) {
        log.info("WebSocket 断开连接");
        handleOnClose(webSocketSession);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    private void dispatchTextMessage(WebSocketSession webSocketSession, TextMessage textMessage) {
        String sessionId = webSocketSession.getId();
        String payload = textMessage.getPayload();
        try {
            // TODO gson 会将 Long 反序列化为 Double
            EventReq eventReq = JsonConverter.jsonToObject(payload, EventReq.class);
            String event = eventReq.getEvent();
            switch (EventType.valueOf(event)) {
                case heartbeat:
                    chatConnection.sendHeartbeatPong(webSocketSession);
                    break;
                case event_contact_apply:
                    log.info("contact_apply event");
                    break;
                case event_talk_keyboard:
                    log.info("talk_keyboard event");
                    break;
                case event_talk:
                    chatService.onEventTalk(eventReq.getData());
                    break;
                case event_talk_revoke:
                    log.info("talk_revoke event");
                    break;
                case event_talk_join_group:
                    log.info("talk_join_group event");
                    break;
                case event_error:
                    log.info("error event");
                    break;
                default:
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void handleOnClose(WebSocketSession webSocketSession) {
        Long userId = chatConnection.getUserId(webSocketSession.getId());
        chatService.onLoginEvent(userId, false);
        chatConnection.removeUserSession(webSocketSession);
    }
}
