package com.ruoyi.web.websocket;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import java.nio.ByteBuffer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.ruoyi.customer.service.ICustomerServiceService;
import com.ruoyi.system.domain.ManualServiceSessions;

/**
 * 客服系统WebSocket服务
 * 
 * @author ruoyi
 */
@ServerEndpoint("/websocket/customer/{userId}")
@Component
public class CustomerServiceWebSocket {
    
    private static final Logger log = LoggerFactory.getLogger(CustomerServiceWebSocket.class);
    
    /** 客服服务 - 使用静态变量以便在WebSocket中使用 */
    private static ICustomerServiceService customerServiceService;
    
    /** 静态变量，用来记录当前在线连接数 */
    private static final AtomicInteger onlineCount = new AtomicInteger(0);
    
    /** concurrent包的线程安全Set，用来存放每个客户端对应的WebSocket对象 */
    private static final ConcurrentHashMap<String, CustomerServiceWebSocket> webSocketMap = new ConcurrentHashMap<>();
    
    /** 心跳定时器 */
    private static final ScheduledExecutorService heartbeatExecutor = Executors.newScheduledThreadPool(10);
    
    /** 心跳间隔时间（秒） */
    private static final int HEARTBEAT_INTERVAL = 30;
    
    /** 连接超时时间（毫秒） */
    private static final long SESSION_TIMEOUT = 300000; // 5分钟
    
    /** 与某个客户端的连接会话，需要通过它来给客户端发送数据 */
    private Session session;
    
    /** 接收userId */
    private String userId = "";
    
    /** 心跳任务 */
    private java.util.concurrent.ScheduledFuture<?> heartbeatTask;
    
    /**
     * 注入客服服务
     */
    @Autowired
    public void setCustomerServiceService(ICustomerServiceService customerServiceService) {
        CustomerServiceWebSocket.customerServiceService = customerServiceService;
    }
    
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        
        // 设置session超时时间
        session.setMaxIdleTimeout(SESSION_TIMEOUT);
        
        if (webSocketMap.containsKey(userId)) {
            // 如果已存在连接，先清理旧的心跳任务
            CustomerServiceWebSocket oldWebSocket = webSocketMap.get(userId);
            if (oldWebSocket != null && oldWebSocket.heartbeatTask != null) {
                oldWebSocket.heartbeatTask.cancel(true);
            }
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
        } else {
            webSocketMap.put(userId, this);
            addOnlineCount();
        }
        
        // 启动心跳机制
        startHeartbeat();
        
        log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount() + ",连接超时设置为:" + SESSION_TIMEOUT + "ms");
        
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("用户:" + userId + ",网络异常!!!!!!");
        }
    }
    
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        // 停止心跳任务
        stopHeartbeat();
        
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            subOnlineCount();
        }
        
        // 清理该用户的待处理转人工记录
        try {
            if (customerServiceService != null && userId != null && !userId.isEmpty()) {
                Long userIdLong = Long.valueOf(userId);
                int cleanedCount = customerServiceService.cleanupPendingManualRequests(userIdLong);
                if (cleanedCount > 0) {
                    log.info("WebSocket断开，已清理用户{}的{}条待处理转人工记录", userId, cleanedCount);
                }
            }
        } catch (Exception e) {
            log.error("清理用户{}的转人工记录失败", userId, e);
        }
        
        log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
    }
    
    /**
     * 处理Pong消息
     */
    @OnMessage
    public void onPong(PongMessage pongMessage, Session session) {
        log.debug("收到用户{}的pong消息，连接正常", this.userId);
    }
    
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:" + userId + ",报文:" + message);
        
        // 解析消息
        if (message != null && !message.isEmpty()) {
            try {
                com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(message);
                String toUserId = jsonObject.getString("toUserId");
                String messageContent = jsonObject.getString("message");
                String messageType = jsonObject.getString("type");
                
                // 处理消息路由
                if ("service".equals(toUserId)) {
                    // 当toUserId为'service'时，根据发送者userId查找对应的客服人员
                    log.info("收到发送给客服的消息，发送者userId: {}", this.userId);
                    
                    // 检查customerServiceService是否为null
                    if (customerServiceService == null) {
                        log.error("customerServiceService为null，无法处理消息路由");
                        return;
                    }
                    log.info("customerServiceService检查通过，开始处理消息路由");
                    
                    try {
                        Long senderUserId = Long.valueOf(this.userId);
                        log.info("准备查询用户{}的已接受转人工会话", senderUserId);
                        
                        // 查找该用户对应的已接受状态的转人工记录
                        ManualServiceSessions acceptedSession = customerServiceService.getAcceptedManualSessionByUserId(senderUserId);
                        log.info("查询已接受转人工会话完成，结果: {}", acceptedSession != null ? "找到会话" : "未找到会话");
                        
                        if (acceptedSession != null) {
                            log.info("已接受会话详情 - manualSessionId: {}, sessionId: {}, userId: {}, serviceId: {}, status: {}", 
                                    acceptedSession.getManualSessionId(), 
                                    acceptedSession.getSessionId(), 
                                    acceptedSession.getUserId(), 
                                    acceptedSession.getServiceId(), 
                                    acceptedSession.getStatus());
                            
                            if (acceptedSession.getServiceId() != null) {
                                String serviceUserId = acceptedSession.getServiceId().toString();
                                log.info("目标客服ID: {}", serviceUserId);
                                
                                // 检查对应的客服是否在线
                                log.info("当前在线用户列表: {}", webSocketMap.keySet());
                                if (webSocketMap.containsKey(serviceUserId)) {
                                    log.info("客服{}在线，准备转发消息", serviceUserId);
                                    webSocketMap.get(serviceUserId).sendMessage(JSON.toJSONString(jsonObject));
                                    log.info("消息已成功转发给对应的客服人员: serviceId={}", serviceUserId);
                                } else {
                                    log.warn("对应的客服人员不在线: serviceId={}, 当前在线用户: {}", serviceUserId, webSocketMap.keySet());
                                }
                            } else {
                                log.warn("已接受会话的serviceId为null");
                            }
                        } else {
                            log.warn("未找到用户{}对应的已接受状态的转人工记录", this.userId);
                        }
                    } catch (NumberFormatException e) {
                        log.error("用户ID格式错误: {}", this.userId, e);
                    } catch (Exception e) {
                        log.error("查找对应客服人员失败，异常详情: ", e);
                    }
                } else if (toUserId != null && webSocketMap.containsKey(toUserId)) {
                    // 正常的点对点消息转发
                    webSocketMap.get(toUserId).sendMessage(JSON.toJSONString(jsonObject));
                    log.info("消息已转发给指定用户: {}", toUserId);
                } else {
                    log.error("请求的userId:" + toUserId + "不在该服务器上");
                }
            } catch (Exception e) {
                log.error("消息解析异常", e);
            }
        }
    }
    
    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }
    
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
    
    /**
     * 发送自定义消息
     */
    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
        log.info("[WebSocket调试] 开始发送消息到用户: {}, 报文: {}", userId, message);
        
        // 打印当前在线用户列表和数量
        log.info("[WebSocket调试] 当前在线用户数量: {}", webSocketMap.size());
        log.info("[WebSocket调试] 当前在线用户列表: {}", webSocketMap.keySet());
        
        // 检查目标用户是否在线
        if (userId != null && webSocketMap.containsKey(userId)) {
            CustomerServiceWebSocket targetWebSocket = webSocketMap.get(userId);
            
            // 检查WebSocket连接状态
            if (targetWebSocket != null && targetWebSocket.session != null) {
                log.info("[WebSocket调试] 用户{}的WebSocket连接状态: isOpen={}, id={}", 
                        userId, targetWebSocket.session.isOpen(), targetWebSocket.session.getId());
                
                try {
                    targetWebSocket.sendMessage(message);
                    log.info("[WebSocket调试] 消息发送成功到用户: {}", userId);
                } catch (IOException e) {
                    log.error("[WebSocket调试] 消息发送失败到用户: {}, 错误: {}", userId, e.getMessage());
                    throw e;
                }
            } else {
                log.error("[WebSocket调试] 用户{}的WebSocket连接为空或session为空", userId);
            }
        } else {
            log.error("[WebSocket调试] 用户{}不在线！在线用户列表: {}", userId, webSocketMap.keySet());
        }
    }
    
    /**
     * 获得此时的在线人数
     */
    public static synchronized int getOnlineCount() {
        return onlineCount.get();
    }
    
    /**
     * 在线人数加1
     */
    public static synchronized void addOnlineCount() {
        onlineCount.incrementAndGet();
    }
    
    /**
     * 在线人数减1
     */
    public static synchronized void subOnlineCount() {
        onlineCount.decrementAndGet();
    }
    
    /**
     * 获取在线用户列表
     */
    public static ConcurrentHashMap<String, CustomerServiceWebSocket> getWebSocketMap() {
        return webSocketMap;
    }
    
    /**
     * 发送消息给指定用户
     */
    public static void sendMessageToUser(String userId, String message) {
        try {
            if (userId != null && webSocketMap.containsKey(userId)) {
                webSocketMap.get(userId).sendMessage(message);
                log.info("已发送消息给用户: userId={}", userId);
            } else {
                log.warn("用户{}不在线，无法发送消息", userId);
            }
        } catch (Exception e) {
            log.error("发送消息给用户{}失败", userId, e);
        }
    }
    
    /**
     * 启动心跳机制
     */
    private void startHeartbeat() {
        if (heartbeatTask != null) {
            heartbeatTask.cancel(true);
        }
        
        heartbeatTask = heartbeatExecutor.scheduleWithFixedDelay(() -> {
            try {
                if (session != null && session.isOpen()) {
                    // 发送ping消息
                    ByteBuffer pingData = ByteBuffer.wrap("ping".getBytes());
                    session.getBasicRemote().sendPing(pingData);
                    log.debug("向用户{}发送ping消息", userId);
                } else {
                    log.warn("用户{}的session已关闭，停止心跳", userId);
                    stopHeartbeat();
                }
            } catch (Exception e) {
                log.error("发送心跳消息失败，用户: {}, 错误: {}", userId, e.getMessage());
                stopHeartbeat();
            }
        }, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
        
        log.info("用户{}启动心跳机制，间隔{}秒", userId, HEARTBEAT_INTERVAL);
    }
    
    /**
     * 停止心跳机制
     */
    private void stopHeartbeat() {
        if (heartbeatTask != null && !heartbeatTask.isCancelled()) {
            heartbeatTask.cancel(true);
            log.info("用户{}停止心跳机制", userId);
        }
    }
    
    /**
     * 发送ping消息保持连接活跃
     */
    public void sendPing() {
        try {
            if (session != null && session.isOpen()) {
                ByteBuffer pingData = ByteBuffer.wrap("heartbeat".getBytes());
                session.getBasicRemote().sendPing(pingData);
                log.debug("向用户{}发送ping消息", userId);
            }
        } catch (Exception e) {
            log.error("发送ping消息失败，用户: {}", userId, e);
        }
    }
}