package com.luojia_channel.modules.message.server;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.luojia_channel.common.utils.RedisUtil;
import com.luojia_channel.modules.message.dto.MessageRequest;
import com.luojia_channel.modules.message.dto.MessageResponse;
import com.luojia_channel.modules.message.entity.MessageDO;
import com.luojia_channel.modules.message.mapper.MessageMapper;
import com.luojia_channel.modules.message.util.WebSocketContext;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/connect/{userId}")
@Slf4j
@Component
public class WebSocketServer {
    // 存储在线用户会话 <userId, Session>
    private final static Map<String, Session> CLIENTS = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(@PathParam("userId") String userId,
                       Session session) {
        // 将新连接加入客户端列表
        CLIENTS.put(userId, session);
        log.info("用户 [{}] 已连接，当前在线人数：{}", userId, CLIENTS.size());
    }

    @OnClose
    public void onClose(@PathParam("userId") String userId,
                        Session session) {
        // 移除断开连接的用户
        CLIENTS.remove(userId);
        log.info("用户 [{}] 已断开，当前在线人数：{}", userId, CLIENTS.size());
    }

    @OnError
    public void onError(@PathParam("userId") String userId,
                        Session session, Throwable e) {
        log.error("用户 [{}] 发生错误: {}", userId, e.getMessage(), e);
        try {
            session.close();
        } catch (IOException ex) {
            log.error("关闭会话失败: {}", ex.getMessage());
        }
    }

    @OnMessage
    public void onMessage(@PathParam("userId") String senderId,
                          String message, Session session) {
        try {
            // 解析客户端发送的 JSON 消息
            MessageRequest request = JSON.parseObject(message, MessageRequest.class);
            switch (request.getMessageType()) {
                case 0 -> sendSystemNotification(request);
                case 1 -> sendPrivateMessage(Long.parseLong(senderId), request);
                default -> log.warn("未知消息类型: {}", request.getMessageType());
            }
        } catch (Exception e) {
            log.error("消息处理失败: {}", e.getMessage());
            sendErrorResponse(session, "消息处理失败，请稍后重试");
        }
    }

    // 发送一对一私信
    public void sendPrivateMessage(Long senderId, MessageRequest request) {
        Long receiverId = request.getReceiverId();
        Session receiverSession = CLIENTS.get(receiverId.toString());
        // 构建私信响应
        MessageResponse response = MessageResponse.builder()
                .messageType(request.getMessageType())
                .content(request.getContent())
                .senderId(senderId)
                .senderName(request.getSenderName())
                .senderAvatar(request.getSenderAvatar())
                .receiverId(receiverId)
                .createTime(LocalDateTime.now())
                .build();

        // 发送给接收方
        if (receiverSession != null && receiverSession.isOpen()) {
            sendMessage(receiverSession, JSON.toJSONString(response));
        } else {
            log.info("接收方 [{}] 不在线，消息无法即时送达", receiverId);
        }
        MessageDO message = BeanUtil.copyProperties(response, MessageDO.class);
        MessageMapper messageMapper = WebSocketContext.getBean(MessageMapper.class);
        RedisUtil redisUtil = WebSocketContext.getBean(RedisUtil.class);
        messageMapper.insert(message);
        sendMessage(CLIENTS.get(senderId.toString()), JSON.toJSONString(response));
        // 存储消息至redis
        if(request.getMessageType().equals(1)){
            String key = "chat:history:" + Math.min(senderId, receiverId) + ":" +Math.max(senderId, receiverId);
            redisUtil.zAdd(key, message.getId(), System.currentTimeMillis());
            String chatListKey = "chat:user_list:" + senderId;
            redisUtil.zAdd(chatListKey, receiverId, System.currentTimeMillis());
            chatListKey = "chat:user_list:" + receiverId;
            redisUtil.zAdd(chatListKey, senderId, System.currentTimeMillis());
        }
    }

    // 发送系统通知
    public void sendSystemNotification(MessageRequest request) {
        MessageResponse response = MessageResponse.builder()
                .senderId(0L)
                .receiverId(0L)
                .messageType(request.getMessageType())
                .content(request.getContent())
                .createTime(LocalDateTime.now())
                .build();
        // 广播给所有在线用户
        for (Session session : CLIENTS.values()) {
            sendMessage(session, JSON.toJSONString(response));
        }
        MessageDO message = BeanUtil.copyProperties(response, MessageDO.class);
        MessageMapper messageMapper = WebSocketContext.getBean(MessageMapper.class);
        messageMapper.insert(message);
    }

    // 安全消息
    private void sendMessage(Session session, String message) {
        try {
            if (session != null && session.isOpen()) {
                session.getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            log.error("发送消息失败: {}", e.getMessage());
        }
    }

    // 发送错误响应
    private void sendErrorResponse(Session session, String errorMessage) {
        MessageResponse errorResponse = MessageResponse.builder()
                .messageType(-1) // 错误消息类型
                .content(errorMessage)
                .createTime(LocalDateTime.now())
                .build();
        sendMessage(session, JSON.toJSONString(errorResponse));
    }
}