/**
 * 自然写互动课堂教学管理云平台软件 V1.0
 * 
 * 消息推送服务
 * 基于 WebSocket 实现多终端实时消息推送
 * 支持新作业通知、批改完成通知、课堂互动指令等
 */
package com.writech.cloud.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.web.socket.config.annotation.*;

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

/**
 * 消息服务类
 * 
 * WebSocket实时消息通道：/ws/v1/notify
 * 
 * 消息类型：
 * - ASSIGNMENT_NEW：新作业通知
 * - ASSIGNMENT_GRADED：批改完成通知
 * - STROKE_REALTIME：实时笔迹数据推送
 * - CLASSROOM_INTERACTION：课堂互动指令
 * - SYSTEM_NOTIFICATION：系统公告
 */
@Service
public class MessageService extends TextWebSocketHandler implements WebSocketConfigurer {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /** 在线用户WebSocket会话映射（userId → session列表，支持多终端同时在线） */
    private final ConcurrentHashMap<String, List<WebSocketSession>> userSessions = 
            new ConcurrentHashMap<>();

    /** 教室频道会话映射（classroomId → session列表） */
    private final ConcurrentHashMap<String, List<WebSocketSession>> classroomChannels = 
            new ConcurrentHashMap<>();

    /**
     * WebSocket端点注册
     */
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(this, "/ws/v1/notify")
                .setAllowedOrigins("*");
    }

    /**
     * WebSocket连接建立
     * 从Token中解析用户ID，注册到在线会话映射
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String userId = extractUserIdFromSession(session);
        if (userId != null) {
            // 注册用户会话
            userSessions.computeIfAbsent(userId, k -> new ArrayList<>()).add(session);
            // 更新在线状态
            updateOnlineStatus(userId, true);
            // 推送离线期间的未读消息
            pushOfflineMessages(userId, session);
        }
    }

    /**
     * WebSocket消息接收
     * 处理客户端发送的消息（心跳、课堂互动指令等）
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) 
            throws Exception {
        String payload = message.getPayload();
        Map<String, Object> msg = parseMessage(payload);
        
        String type = (String) msg.get("type");
        if (type == null) return;

        switch (type) {
            case "HEARTBEAT":
                // 回复心跳
                session.sendMessage(new TextMessage("{\"type\":\"HEARTBEAT_ACK\"}"));
                break;
            case "JOIN_CLASSROOM":
                // 加入教室频道（课堂互动场景）
                String classroomId = (String) msg.get("classroomId");
                joinClassroomChannel(classroomId, session);
                break;
            case "LEAVE_CLASSROOM":
                // 离开教室频道
                String leaveClassroom = (String) msg.get("classroomId");
                leaveClassroomChannel(leaveClassroom, session);
                break;
            case "CLASSROOM_COMMAND":
                // 教师发送课堂控制指令（广播至教室内所有终端）
                broadcastToClassroom(msg);
                break;
            default:
                break;
        }
    }

    /**
     * WebSocket连接断开
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) 
            throws Exception {
        String userId = extractUserIdFromSession(session);
        if (userId != null) {
            // 移除会话
            List<WebSocketSession> sessions = userSessions.get(userId);
            if (sessions != null) {
                sessions.remove(session);
                if (sessions.isEmpty()) {
                    userSessions.remove(userId);
                    updateOnlineStatus(userId, false);
                }
            }
        }
        // 从教室频道移除
        classroomChannels.values().forEach(list -> list.remove(session));
    }

    /**
     * 向指定用户推送消息
     * 支持多终端同时推送（手机/Pad/PC同时在线时都能收到）
     * 
     * @param userId 目标用户ID
     * @param messageType 消息类型
     * @param data 消息数据
     */
    public void pushToUser(String userId, String messageType, Map<String, Object> data) {
        Map<String, Object> message = new HashMap<>();
        message.put("type", messageType);
        message.put("data", data);
        message.put("timestamp", System.currentTimeMillis());

        String json = toJson(message);
        List<WebSocketSession> sessions = userSessions.get(userId);

        if (sessions != null && !sessions.isEmpty()) {
            // 在线推送
            for (WebSocketSession session : sessions) {
                try {
                    if (session.isOpen()) {
                        session.sendMessage(new TextMessage(json));
                    }
                } catch (IOException e) {
                    // 发送失败，记录日志
                }
            }
        } else {
            // 离线存储（用户上线后推送）
            storeOfflineMessage(userId, json);
        }
    }

    /**
     * 向班级所有学生推送消息
     * 
     * @param classId 班级ID
     * @param messageType 消息类型
     * @param data 消息数据
     */
    public void pushToClass(String classId, String messageType, Map<String, Object> data) {
        // 查询班级学生列表
        // List<String> studentIds = classService.getStudentIds(classId);
        List<String> studentIds = new ArrayList<>();
        for (String studentId : studentIds) {
            pushToUser(studentId, messageType, data);
        }
    }

    /**
     * 向教室频道广播消息
     * 用于课堂互动场景，将消息推送至教室内所有终端（黑板/PC/电视/Pad）
     */
    public void broadcastToClassroom(Map<String, Object> message) {
        String classroomId = (String) message.get("classroomId");
        if (classroomId == null) return;

        String json = toJson(message);
        List<WebSocketSession> sessions = classroomChannels.get(classroomId);
        if (sessions != null) {
            for (WebSocketSession session : sessions) {
                try {
                    if (session.isOpen()) {
                        session.sendMessage(new TextMessage(json));
                    }
                } catch (IOException e) {
                    // 发送失败处理
                }
            }
        }
    }

    /**
     * 推送作业发布通知
     */
    public void pushAssignmentNotification(String classId, String title, String assignmentId) {
        Map<String, Object> data = new HashMap<>();
        data.put("assignmentId", assignmentId);
        data.put("title", title);
        data.put("message", "教师发布了新作业: " + title);
        pushToClass(classId, "ASSIGNMENT_NEW", data);
    }

    /**
     * 推送批改完成通知
     */
    public void pushGradingNotification(String studentId, String assignmentTitle, 
                                         double score) {
        Map<String, Object> data = new HashMap<>();
        data.put("title", assignmentTitle);
        data.put("score", score);
        data.put("message", "作业\"" + assignmentTitle + "\"批改完成，得分: " + score);
        pushToUser(studentId, "ASSIGNMENT_GRADED", data);
    }

    /**
     * 推送实时笔迹数据至教室大屏
     * 低延迟推送，用于黑板/电视大屏实时展示学生书写过程
     */
    public void pushRealtimeStroke(String classroomId, String studentId, 
                                    List<Map<String, Object>> strokePoints) {
        Map<String, Object> data = new HashMap<>();
        data.put("studentId", studentId);
        data.put("points", strokePoints);
        
        Map<String, Object> message = new HashMap<>();
        message.put("type", "STROKE_REALTIME");
        message.put("classroomId", classroomId);
        message.put("data", data);
        
        broadcastToClassroom(message);
    }

    // ==================== 内部方法 ====================

    /** 加入教室频道 */
    private void joinClassroomChannel(String classroomId, WebSocketSession session) {
        classroomChannels.computeIfAbsent(classroomId, k -> new ArrayList<>()).add(session);
    }

    /** 离开教室频道 */
    private void leaveClassroomChannel(String classroomId, WebSocketSession session) {
        List<WebSocketSession> sessions = classroomChannels.get(classroomId);
        if (sessions != null) {
            sessions.remove(session);
        }
    }

    /** 从WebSocket会话中提取用户ID */
    private String extractUserIdFromSession(WebSocketSession session) {
        // 从URL参数或握手头中的Token解析用户ID
        String query = session.getUri() != null ? session.getUri().getQuery() : null;
        if (query != null && query.contains("token=")) {
            // 解析Token获取userId
            return "extracted_user_id";
        }
        return null;
    }

    /** 更新用户在线状态 */
    private void updateOnlineStatus(String userId, boolean online) {
        String key = "writech:user:online:" + userId;
        if (online) {
            redisTemplate.opsForValue().set(key, "1");
        } else {
            redisTemplate.delete(key);
        }
    }

    /** 存储离线消息 */
    private void storeOfflineMessage(String userId, String message) {
        String key = "writech:offline:msg:" + userId;
        redisTemplate.opsForList().rightPush(key, message);
        // 最多保留100条离线消息
        redisTemplate.opsForList().trim(key, -100, -1);
    }

    /** 推送离线期间积累的未读消息 */
    private void pushOfflineMessages(String userId, WebSocketSession session) 
            throws IOException {
        String key = "writech:offline:msg:" + userId;
        List<String> messages = redisTemplate.opsForList().range(key, 0, -1);
        if (messages != null) {
            for (String msg : messages) {
                session.sendMessage(new TextMessage(msg));
            }
            redisTemplate.delete(key);
        }
    }

    /** JSON序列化（简化版本） */
    private String toJson(Map<String, Object> map) {
        StringBuilder sb = new StringBuilder("{");
        boolean first = true;
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (!first) sb.append(",");
            sb.append("\"").append(entry.getKey()).append("\":");
            Object value = entry.getValue();
            if (value instanceof String) {
                sb.append("\"").append(value).append("\"");
            } else {
                sb.append(value);
            }
            first = false;
        }
        sb.append("}");
        return sb.toString();
    }

    /** JSON解析（简化版本） */
    private Map<String, Object> parseMessage(String json) {
        return new HashMap<>();
    }

    /**
     * 获取在线用户统计
     */
    public Map<String, Integer> getOnlineStats() {
        Map<String, Integer> stats = new HashMap<>();
        stats.put("totalOnlineUsers", userSessions.size());
        stats.put("totalSessions", userSessions.values().stream()
                .mapToInt(List::size).sum());
        stats.put("activeClassrooms", classroomChannels.size());
        return stats;
    }
}
