package com.ecep.contract.handler;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
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.IEntityService;
import com.ecep.contract.PageArgument;
import com.ecep.contract.QueryService;
import com.ecep.contract.SpringApp;
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.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import lombok.Data;

/**
 * WebSocket处理器
 * 处理与客户端的WebSocket连接、消息传递和断开连接
 */
@Component
public class WebSocketHandler extends TextWebSocketHandler {

    private final ObjectMapper objectMapper;

    private static final Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);

    @Autowired
    private EmployeeLoginHistoryService employeeLoginHistoryService;
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

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

    @Data
    static class SessionInfo {
        private Integer employeeId;
        private Integer loginHistoryId;
        private WebSocketSession session;
        private ScheduledFuture<?> schedule;

        void click() {
            try {
                session.sendMessage(new PingMessage(ByteBuffer.wrap("ping".getBytes())));
            } catch (IOException e) {
                logger.error("发送ping消息失败 (会话ID: " + session.getId() + "): " + e.getMessage(), e);
            }
        }
    }

    WebSocketHandler(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    /**
     * 连接建立时调用
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 添加会话到活跃会话集合
        SessionInfo sessionInfo = new SessionInfo();
        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, 401, "会话未绑定用户");
            session.close();
            return;
        }

        activeSessions.put(sessionInfo.getEmployeeId(), sessionInfo);
        System.out.println(sessionInfo.getLoginHistoryId());
        System.out.println(sessionInfo.getEmployeeId());

        logger.info("WebSocket连接已建立: " + session.getId());

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

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

    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("errorCode", errorCode);
            objectNode.put("success", false);
            objectNode.put("message", 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);
        }
    }

    /**
     * 接收文本消息时调用
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        logger.info("收到来自客户端的消息: " + payload + " (会话ID: " + 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;
        }

        if (handleAsMessageCallback(session, payload)) {
            return;
        }

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

    private boolean handleAsMessageCallback(WebSocketSession session, String payload) {
        if (session == null || !session.isOpen()) {
            logger.warn("尝试在已关闭的WebSocket会话上处理消息回调");
            return false;
        }

        JsonNode jsonNode = null;
        try {
            jsonNode = objectMapper.readTree(payload);
        } catch (Exception e) {
            logger.warn("解析消息回调JSON失败: {}", payload, e);
            return false;
        }

        if (!jsonNode.has("messageId")) {
            // 没有 messageId 的消息不处理
            return false;
        }
        String messageId = jsonNode.get("messageId").asText();

        if (!jsonNode.has("service")) {
            sendError(session, messageId, "缺失 service 参数");
            return true;
        }

        String serviceName = jsonNode.get("service").asText();
        Object service = null;
        try {
            service = SpringApp.getBean(serviceName);
        } catch (Exception e) {
            sendError(session, messageId, "未找到服务: " + serviceName);
            return true;
        }

        if (!jsonNode.has("method")) {
            sendError(session, messageId, "缺失 method 参数");
            return true;
        }

        String methodName = jsonNode.get("method").asText();

        try {
            Object result = null;
            if (methodName.equals("findAll")) {
                result = invokerFindAllMethod(service, jsonNode.get("arguments"));
            } else if (methodName.equals("findById")) {
                result = invokerFindByIdMethod(service, jsonNode.get("arguments"));
            } else if (methodName.equals("save")) {
                result = invokerSaveMethod(service, jsonNode.get("arguments"));
            } else if (methodName.equals("delete")) {
                result = invokerDeleteMethod(service, jsonNode.get("arguments"));
            } else {
                sendError(session, messageId, "未实现的方法: " + methodName);
                return true;
            }

            // 再次检查会话状态
            if (!session.isOpen()) {
                logger.warn("会话已关闭，无法发送处理结果 (消息ID: {})");
                return true;
            }

            ObjectNode objectNode = objectMapper.createObjectNode();
            objectNode.put("messageId", messageId);
            objectNode.set("data", objectMapper.valueToTree(result));
            String response = objectMapper.writeValueAsString(objectNode);
            session.sendMessage(new TextMessage(response));
            return true;
        } catch (Exception e) {
            // 防止重复发送消息导致的TEXT_PARTIAL_WRITING异常
            if (!session.isOpen()) {
                logger.warn("会话已关闭，无法发送错误消息 (消息ID: {})");
            } else {
                sendError(session, messageId, e.getMessage());
            }
            logger.error("处理消息回调失败 (消息ID: {})", messageId, e);
            return true;
        }
    }

    private Object invokerDeleteMethod(Object service, JsonNode argumentsNode) {
        JsonNode paramsNode = argumentsNode.get(0);
        if (!paramsNode.has("id")) {
            throw new IllegalArgumentException("缺失 id 参数");
        }
        int id = paramsNode.get("id").asInt();
        IEntityService<Object> entityService = (IEntityService<Object>) service;
        Object entity = entityService.findById(id);
        if (entity == null) {
            throw new NoSuchElementException("未找到实体: #" + id);
        }
        entityService.delete(entity);
        return entity;
    }

    private Object invokerSaveMethod(Object service, JsonNode argumentsNode) throws JsonMappingException {
        JsonNode paramsNode = argumentsNode.get(0);
        IEntityService<Object> entityService = (IEntityService<Object>) service;
        Object entity = null;
        if (paramsNode.has("id")) {
            int id = paramsNode.get("id").asInt();
            entity = entityService.findById(id);
            if (entity == null) {
                throw new NoSuchElementException("未找到实体: #" + id);
            }
        } else {
            entity = createNewEntity(entityService);
            if (entity == null) {
                throw new UnsupportedOperationException("无法创建实体对象, " + service.getClass().getName());
            }
        }
        objectMapper.updateValue(entity, paramsNode);
        return entityService.save(entity);
    }

    private Object createNewEntity(IEntityService<Object> entityService) {
        try {
            Type[] types = getClass().getGenericInterfaces();
            // System.out.println("types = " + Arrays.asList(types));
            if (types.length > 0) {
                String typeName = types[0].getTypeName();
                // System.out.println("typeName = " + typeName);
                String clz = typeName.split("<")[1].split(">")[0].split(",")[0].trim();
                // System.out.println("clz = " + clz);
                Class<?> clazz = Class.forName(clz);
                return (T) clazz.getDeclaredConstructor().newInstance();
            }
        } catch (Exception e) {
            throw new RuntimeException("无法创建Entity实例", e);
        }
        return null;
    }

    /*
     * see client QueryService#findById(Integer)
     */
    private Object invokerFindByIdMethod(Object service, JsonNode argumentsNode) {
        JsonNode paramsNode = argumentsNode.get(0);
        Integer id = paramsNode.asInt();
        IEntityService<?> entityService = (IEntityService<?>) service;
        return entityService.findById(id);
    }

    private Object invokerFindAllMethod(Object service, JsonNode argumentsNode) throws JsonProcessingException {
        JsonNode paramsNode = argumentsNode.get(0);
        JsonNode pageableNode = argumentsNode.get(1);
        PageArgument pageArgument = objectMapper.treeToValue(pageableNode, PageArgument.class);
        QueryService<?> entityService = (QueryService<?>) service;
        return entityService.findAll(paramsNode, pageArgument.toPageable());
    }

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

        try {
            ObjectNode objectNode = objectMapper.createObjectNode();
            objectNode.put("messageId", messageId);
            objectNode.put("success", false);
            objectNode.put("message", 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);
        }
    }

    @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() + ")");
    }

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

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

        Integer loginHistoryId = sessionInfo.getLoginHistoryId();
        if (loginHistoryId != null) {
            EmployeeLoginHistory history = employeeLoginHistoryService.findById(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();
    }
}