package com.ecep.contract.handler;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.ecep.contract.constant.WebSocketConstant;
import com.ecep.contract.ds.other.service.EmployeeLoginHistoryService;
import com.ecep.contract.ds.other.service.EmployeeService;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.EmployeeLoginHistory;
import com.ecep.contract.service.WebSocketServerCallbackManager;
import com.ecep.contract.service.tasker.WebSocketServerTaskManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * WebSocket处理器
 * 处理与客户端的WebSocket连接、消息传递和断开连接
 */
@Component
public class WebSocketServerHandler extends TextWebSocketHandler {
    static final Logger logger = LoggerFactory.getLogger(WebSocketServerHandler.class);

    private final AuthenticationManager authenticationManager;
    private final ObjectMapper objectMapper;

    @Autowired
    private EmployeeLoginHistoryService employeeLoginHistoryService;
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;
    @Autowired
    private WebSocketServerTaskManager taskManager;
    @Autowired
    private WebSocketServerCallbackManager callbackManager;

    // 存储所有活跃的WebSocket会话
    private final Map<Integer, SessionInfo> activeSessions = Collections.synchronizedMap(new HashMap<>());

    WebSocketServerHandler(ObjectMapper objectMapper, AuthenticationManager authenticationManager) {
        this.objectMapper = objectMapper;
        this.authenticationManager = authenticationManager;
    }

    /**
     * 连接建立时调用
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 添加会话到活跃会话集合
        SessionInfo sessionInfo = new SessionInfo();
        sessionInfo.setObjectMapper(objectMapper);
        sessionInfo.setSession(session);
        sessionInfo.setLoginHistoryId((Integer) session.getAttributes().get("loginHistoryId"));
        sessionInfo.setEmployeeId((Integer) session.getAttributes().get("employeeId"));

        if (sessionInfo.getEmployeeId() == null) {
            logger.error("会话未绑定用户: {}", session.getId());
            sendError(session, WebSocketConstant.ERROR_CODE_UNAUTHORIZED, "会话未绑定用户");
            // session.close(CloseStatus.NOT_ACCEPTABLE);
            return;
        }

        activeSessions.put(sessionInfo.getEmployeeId(), sessionInfo);
        logger.info("WebSocket连接已建立: {}", session.getId());

        Employee employee = employeeService.getById(sessionInfo.getEmployeeId());
        if (employee == null) {
            logger.error("未找到用户: #{}", sessionInfo.getEmployeeId());
            return;
        }

        ScheduledFuture<?> schedule = scheduledExecutorService.schedule(sessionInfo::click, 30, TimeUnit.SECONDS);
        sessionInfo.setPingPongScheduledFuture(schedule);
    }

    /**
     * 接收文本消息时调用
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        if (logger.isInfoEnabled()) {
            logger.info("收到来自客户端的消息: {} (会话ID: {})", payload, session.getId());
        }
        // 处理文本格式的ping消息
        if ("ping".equals(payload)) {
            // 回复文本格式的pong消息
            try {
                session.sendMessage(new TextMessage("pong"));
                logger.info("发送pong响应到会话: " + session.getId());
            } catch (IOException e) {
                logger.error("发送pong响应失败 (会话ID: " + session.getId() + "): " + e.getMessage(), e);
            }
            return;
        }

        // 尝试将消息作为JSON处理
        if (handleAsJson(session, payload)) {
            return;
        }

        // 处理其他类型的文本消息
        logger.info("处理普通消息: " + payload);
    }

    private boolean handleAsJson(WebSocketSession session, String payload) {
        if (!session.isOpen()) {
            logger.warn("尝试在已关闭的WebSocket会话[{}]上处理消息回调", session.getId());
            return true;
        }

        SessionInfo sessionInfo = activeSessions.get(session.getAttributes().get("employeeId"));
        if (sessionInfo == null) {
            logger.error("未绑定用户: {}", session.getId());
            sendError(session, WebSocketConstant.ERROR_CODE_UNAUTHORIZED, "会话未绑定用户");
            // session.close(CloseStatus.NOT_ACCEPTABLE);
            return true;
        }

        JsonNode jsonNode = null;
        try {
            jsonNode = objectMapper.readTree(payload);
        } catch (JsonProcessingException e) {
            if (payload.startsWith("[") || payload.startsWith("{")) {
                logger.warn("解析消息回调JSON失败: {}", payload, e);
                // 全局错误
                try {
                    sessionInfo.sendError(WebSocketConstant.ERROR_CODE_INTERNAL_SERVER_ERROR, "JSON格式错误");
                } catch (IOException e1) {
                    logger.error("发送错误消息失败: {}", e1.getMessage(), e1);
                }
                return true;
            }
            return false;
        } catch (Exception e) {
            logger.warn("解析消息回调JSON失败: {}", payload, e);
            return false;
        }

        if (jsonNode.has(WebSocketConstant.MESSAGE_ID_FIELD_NAME)) {
            callbackManager.onMessage(sessionInfo, jsonNode);
            return true;
        }
        if (jsonNode.has(WebSocketConstant.SESSION_ID_FIELD_NAME)) {
            taskManager.onMessage(sessionInfo, jsonNode);
            return true;
        }
        return false;
    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
        logger.info("收到来自客户端的二进制消息: " + message.getPayload() + " (会话ID: " + session.getId() + ")");
        // 处理二进制消息
        // 例如，将字节数组转换为字符串
        String binaryData = new String(message.getPayload().array());
        logger.info("二进制消息内容: " + binaryData);
    }

    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        logger.info("收到来自客户端的Pong消息: " + message.getPayload() + " (会话ID: " + session.getId() + ")");

        // 从活跃会话集合中移除会话
        SessionInfo sessionInfo = activeSessions.get((Integer) session.getAttributes().get("employeeId"));
        if (sessionInfo == null) {
            logger.warn("收到来自客户端的Pong消息，但会话不存在: " + session.getId());
            return;
        }
        Integer loginHistoryId = sessionInfo.getLoginHistoryId();
        if (loginHistoryId != null) {
            EmployeeLoginHistory history = employeeLoginHistoryService.getById(loginHistoryId);
            history.setActiveTime(LocalDateTime.now());
            employeeLoginHistoryService.save(history);
        }
    }

    /**
     * 连接关闭时调用
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

        logger.info(
                "WebSocket连接已关闭: " + session.getId() + ", 状态码: " + status.getCode() + ", 原因: " + status.getReason());
        // 从活跃会话集合中移除会话
        SessionInfo sessionInfo = activeSessions.remove((Integer) session.getAttributes().get("employeeId"));
        if (sessionInfo == null) {
            return;
        }
        ScheduledFuture<?> schedule = sessionInfo.getPingPongScheduledFuture();
        if (schedule != null) {
            schedule.cancel(true);
            sessionInfo.setPingPongScheduledFuture(null);
        }

        Integer loginHistoryId = sessionInfo.getLoginHistoryId();
        if (loginHistoryId != null) {
            EmployeeLoginHistory history = employeeLoginHistoryService.getById(loginHistoryId);
            history.setActiveTime(LocalDateTime.now());
            employeeLoginHistoryService.save(history);
        }

    }

    /**
     * 处理传输错误
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        logger.error("WebSocket传输错误 (会话ID: " + session.getId() + "): " + exception.getMessage(), exception);
        // 连接出错时关闭会话
        if (session.isOpen()) {
            session.close(CloseStatus.SERVER_ERROR);
        }
    }

    /**
     * 向所有连接的客户端广播消息
     */
    public void broadcast(TextMessage message) {
        synchronized (activeSessions) {
            for (SessionInfo sessionInfo : activeSessions.values()) {
                WebSocketSession session = sessionInfo.getSession();
                if (session.isOpen()) {
                    try {
                        session.sendMessage(message);
                        logger.info("广播消息到会话: " + session.getId());
                    } catch (IOException e) {
                        logger.error("广播消息失败 (会话ID: " + session.getId() + "): " + e.getMessage(), e);
                    }
                }
            }
        }
    }

    /**
     * 获取当前活跃会话数
     */
    public int getActiveSessionCount() {
        return activeSessions.size();
    }

    private void sendError(WebSocketSession session, int errorCode, String message) {
        if (session == null || !session.isOpen()) {
            logger.warn("尝试向已关闭的WebSocket会话发送错误消息: {}", message);
            return;
        }

        try {
            ObjectNode objectNode = objectMapper.createObjectNode();
            objectNode.put(WebSocketConstant.ERROR_CODE_FIELD_NAME, errorCode);
            objectNode.put(WebSocketConstant.SUCCESS_FIELD_NAME, false);
            objectNode.put(WebSocketConstant.MESSAGE_FIELD_NAME, message);
            String errorMessage = objectMapper.writeValueAsString(objectNode);

            // 检查会话状态并尝试发送错误消息
            if (session.isOpen()) {
                session.sendMessage(new TextMessage(errorMessage));
            } else {
                logger.warn("会话已关闭，无法发送错误消息: {}", message);
            }
        } catch (Exception e) {
            // 捕获所有可能的异常，防止影响主流程
            logger.error("发送错误消息失败 (会话ID: {})", session.getId(), e);
        }
    }
}