/**
 * WebSocket Hook - TCP代理连接管理
 *
 * 提供WebSocket连接的统一管理，用于与TCP代理服务器进行通信
 *
 * 数据格式规范：
 * ```json
 * {
 *   "_from": "dev|setup|...",  // 数据来源: dev=设备, setup=上位机
 *   "cmd": "getBase|setConfig|...",  // 具体命令
 *   "values": {}  // 命令参数或数据
 * }
 * ```
 *
 * 使用方法：
 *
 * 1. 在根组件中使用WebSocketProvider包装：
 * ```jsx
 * import { WebSocketProvider } from './actions/websocket.jsx';
 *
 * const App = () => {
 *   return (
 *     <WebSocketProvider>
 *       <YourComponents />
 *     </WebSocketProvider>
 *   );
 * };
 * ```
 *
 * 2. 基本使用：
 * ```jsx
 * import { useWebSocket } from './actions/websocket.jsx';
 *
 * const MyComponent = () => {
 *   const { isConnected, sendMessage, lastMessage } = useWebSocket();
 *
 *   const handleSendCommand = () => {
 *     sendMessage(JSON.stringify({
 *       _from: 'setup',
 *       cmd: 'setConfig',
 *       values: { x: 100, y: 200 }
 *     }));
 *   };
 *
 *   return (
 *     <div>
 *       <button onClick={handleSendCommand} disabled={!isConnected}>
 *         发送配置
 *       </button>
 *       <div>最新消息: {JSON.stringify(lastMessage)}</div>
 *     </div>
 *   );
 * };
 * ```
 *
 * 3. 订阅特定来源和命令的消息：
 * ```jsx
 * import { useWebSocketSubscription } from './actions/websocket.jsx';
 *
 * const DeviceDataComponent = () => {
 *   只监听设备发送的基础数据
 *   const baseData = useWebSocketSubscription('dev', 'getBase');
 *
 *   监听所有设备消息
 *   const allDeviceData = useWebSocketSubscription('dev');
 *
 *   监听特定命令（任何来源）
 *   const configData = useWebSocketSubscription(null, 'setConfig');
 *
 *   return (
 *     <div>
 *       <h3>设备基础数据:</h3>
 *       <pre>{JSON.stringify(baseData, null, 2)}</pre>
 *     </div>
 *   );
 * };
 * ```
 *
 * 4. 自定义消息处理：
 * ```jsx
 * import { useWebSocketMessage } from './actions/websocket.jsx';
 *
 * const CustomHandler = () => {
 *   useWebSocketMessage(({ _from, cmd, values, timestamp }) => {
 *     if (_from === 'dev' && cmd === 'alarm') {
 *       处理设备告警
 *       handleDeviceAlarm(values);
 *     }
 *   });
 *
 *   return <div>监听中...</div>;
 * };
 * ```
 *
 * API说明：
 * - isConnected: boolean - 连接状态
 * - connectionStatus: string - 连接状态('connecting'|'connected'|'disconnected'|'error')
 * - sendMessage: (message: string) => boolean - 发送消息
 * - lastMessage: object - 最后接收的消息
 * - messageHistory: array - 消息历史
 * - subscribe: (from, cmd, callback) => unsubscribe - 订阅消息
 * - useWebSocketSubscription: (from, cmd) => data - 订阅Hook
 * - useWebSocketMessage: (callback) => void - 消息监听Hook
 *
 * 特性：
 * - 基于 _from 和 cmd 的发布订阅模式
 * - 自动连接和重连（最多5次）
 * - 消息类型过滤和路由
 * - 多组件共享同一WebSocket连接
 * - 完整的连接生命周期管理
 */

import React, {
   createContext,
   useContext,
   useEffect,
   useRef,
   useState,
   useCallback,
} from "react";

// 创建WebSocket Context
const WebSocketContext = createContext();

// WebSocket Provider组件
export const WebSocketProvider = ({ children }) => {
   const [isConnected, setIsConnected] = useState(false);
   const [connectionStatus, setConnectionStatus] = useState("disconnected");
   const [lastMessage, setLastMessage] = useState(null); // 最后接收的消息
   const [messageHistory, setMessageHistory] = useState([]); // 消息历史
   const socketRef = useRef(null);
   const reconnectTimeoutRef = useRef(null);
   const reconnectAttemptsRef = useRef(0);
   const subscriptionsRef = useRef(new Map()); // 订阅器存储
   const maxReconnectAttempts = 5;
   const reconnectInterval = 3000; // 3秒
   const maxHistoryLength = 100; // 最大历史消息数量

   // 动态获取WebSocket连接地址，支持局域网访问
   const getWebSocketUrl = () => {
      const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
      const host = window.location.hostname;
      const port = Number(window.location.port) + 1 || 8081;
      return `${protocol}//${host}:${port}/tcp-proxy`;
   };

   const websocketUrl = getWebSocketUrl();

   // 生成订阅key
   const getSubscriptionKey = (from, cmd) => {
      if (from && cmd) return `${from}:${cmd}`;
      if (from) return `${from}:*`;
      if (cmd) return `*:${cmd}`;
      return "*:*";
   };

   // 订阅消息
   const subscribe = useCallback((from, cmd, callback) => {
      const key = getSubscriptionKey(from, cmd);

      if (!subscriptionsRef.current.has(key)) {
         subscriptionsRef.current.set(key, new Set());
      }

      subscriptionsRef.current.get(key).add(callback);

      // 返回取消订阅函数
      return () => {
         const callbacks = subscriptionsRef.current.get(key);
         if (callbacks) {
            callbacks.delete(callback);
            if (callbacks.size === 0) {
               subscriptionsRef.current.delete(key);
            }
         }
      };
   }, []);

   // 通知订阅者
   const notifySubscribers = useCallback((messageData) => {
      const { _from, cmd } = messageData;

      // 可能匹配的订阅key列表
      const keysToCheck = [
         getSubscriptionKey(_from, cmd), // 精确匹配
         getSubscriptionKey(_from, null), // 匹配来源
         getSubscriptionKey(null, cmd), // 匹配命令
         getSubscriptionKey(null, null), // 匹配所有
      ];

      keysToCheck.forEach((key) => {
         const callbacks = subscriptionsRef.current.get(key);
         if (callbacks) {
            callbacks.forEach((callback) => {
               try {
                  callback(messageData);
               } catch (error) {
                  console.error("订阅回调执行错误:", error);
               }
            });
         }
      });
   }, []);

   // 处理接收到的消息
   const handleMessage = useCallback(
      (data) => {
         const timestamp = Date.now();
         let parsedData = null;

         try {
            parsedData = JSON.parse(data);

            // 验证数据格式
            if (!parsedData._from || !parsedData.cmd) {
               console.warn("收到格式不正确的消息:", parsedData);
               return;
            }

            // console.log(`收到消息 [${parsedData._from}:${parsedData.cmd}]:`, parsedData);
         } catch (error) {
            console.error("解析WebSocket消息失败:", error, data);
            return;
         }

         const messageData = {
            id: `msg_${timestamp}`,
            timestamp,
            rawData: data,
            ...parsedData,
         };

         // 更新最后消息和历史
         setLastMessage(messageData);
         setMessageHistory((prev) => {
            const newHistory = [messageData, ...prev];
            return newHistory.slice(0, maxHistoryLength);
         });

         // 通知订阅者
         notifySubscribers(messageData);
      },
      [notifySubscribers]
   );

   // 发送消息
   const sendMessage = useCallback((message) => {
      if (socketRef.current?.readyState === WebSocket.OPEN) {
         try {
            socketRef.current.send(message);
            //   console.log('发送WebSocket消息:', message);
            return true;
         } catch (error) {
            console.error("发送WebSocket消息失败:", error);
            return false;
         }
      } else {
         console.warn("WebSocket未连接，无法发送消息");
         return false;
      }
   }, []);

   // 连接WebSocket
   const connect = useCallback(() => {
      if (socketRef.current?.readyState === WebSocket.OPEN) {
         return; // 已经连接
      }

      setConnectionStatus("connecting");
      console.log("尝试连接WebSocket:", websocketUrl);

      try {
         socketRef.current = new WebSocket(websocketUrl);

         socketRef.current.onopen = () => {
            console.log("WebSocket连接已建立");
            setIsConnected(true);
            setConnectionStatus("connected");
            reconnectAttemptsRef.current = 0;

            // 发送初始消息或心跳
            //   sendMessage(JSON.stringify({
            //     _from: 'setup',
            //     cmd: 'init',
            //     values: { timestamp: Date.now() }
            //   }));
         };

         socketRef.current.onmessage = (event) => {
            try {
               const data =
                  typeof event.data === "string" ? event.data : event.data;

               // 这里可以处理接收到的消息，比如更新全局状态
               // 或者触发自定义事件
               handleMessage(data);
            } catch (error) {
               console.error("处理WebSocket消息错误:", error);
            }
         };

         socketRef.current.onclose = (event) => {
            console.log("WebSocket连接已关闭:", event.code, event.reason);
            setIsConnected(false);
            setConnectionStatus("disconnected");

            // 自动重连逻辑
            if (reconnectAttemptsRef.current < maxReconnectAttempts) {
               reconnectAttemptsRef.current++;
               console.log(
                  `尝试重连 ${reconnectAttemptsRef.current}/${maxReconnectAttempts}`
               );
               reconnectTimeoutRef.current = setTimeout(() => {
                  connect();
               }, reconnectInterval);
            } else {
               console.log("达到最大重连次数，停止重连");
               setConnectionStatus("error");
            }
         };

         socketRef.current.onerror = (error) => {
            console.error("WebSocket错误:", error);
            setConnectionStatus("error");
         };
      } catch (error) {
         console.error("创建WebSocket连接失败:", error);
         setConnectionStatus("error");
      }
   }, [handleMessage, sendMessage]);

   // 断开连接
   const disconnect = useCallback(() => {
      if (reconnectTimeoutRef.current) {
         clearTimeout(reconnectTimeoutRef.current);
      }

      if (socketRef.current) {
         socketRef.current.close(1000, "用户主动断开");
         socketRef.current = null;
      }

      setIsConnected(false);
      setConnectionStatus("disconnected");
      reconnectAttemptsRef.current = 0;
   }, []);

   // 获取特定来源和命令的消息历史
   const getMessages = useCallback(
      (from, cmd) => {
         return messageHistory.filter((msg) => {
            if (from && cmd) return msg._from === from && msg.cmd === cmd;
            if (from) return msg._from === from;
            if (cmd) return msg.cmd === cmd;
            return true;
         });
      },
      [messageHistory]
   );

   // 清空消息历史
   const clearMessageHistory = useCallback(() => {
      setMessageHistory([]);
      setLastMessage(null);
   }, []);

   // 组件挂载时自动连接
   useEffect(() => {
      connect();

      // 组件卸载时清理
      return () => {
         if (reconnectTimeoutRef.current) {
            clearTimeout(reconnectTimeoutRef.current);
         }
         if (socketRef.current) {
            socketRef.current.close();
         }
      };
   }, [connect]);

   // 提供给子组件的值
   const value = {
      // 连接状态
      isConnected,
      connectionStatus,

      // 连接控制
      connect,
      disconnect,
      sendMessage,

      // 数据访问
      lastMessage,
      messageHistory,
      getMessages,
      clearMessageHistory,

      // 订阅功能
      subscribe,

      // 原始socket
      socket: socketRef.current,
   };

   return (
      <WebSocketContext.Provider value={value}>
         {children}
      </WebSocketContext.Provider>
   );
};

// 自定义Hook，方便子组件使用
export const useWebSocket = () => {
   const context = useContext(WebSocketContext);
   if (!context) {
      throw new Error("useWebSocket必须在WebSocketProvider内部使用");
   }
   return context;
};

// 订阅特定来源和命令的消息Hook
export const useWebSocketSubscription = (from = null, cmd = null) => {
   const { subscribe, getMessages } = useWebSocket();
   const [data, setData] = useState([]);
   const [latestMessage, setLatestMessage] = useState(null);

   useEffect(() => {
      // 获取历史消息
      const history = getMessages(from, cmd);
      setData(history);
      setLatestMessage(history[0] || null);

      // 订阅新消息
      const unsubscribe = subscribe(from, cmd, (messageData) => {
         setLatestMessage(messageData);
         setData((prev) => [messageData, ...prev.slice(0, 99)]); // 保持最多100条
      });

      return unsubscribe;
   }, [subscribe, getMessages, from, cmd]);

   return {
      data, // 所有匹配的消息
      latest: latestMessage, // 最新的消息
      values: latestMessage?.values || null, // 最新消息的values字段
   };
};

// 通用消息监听Hook
export const useWebSocketMessage = (callback) => {
   const { subscribe } = useWebSocket();

   useEffect(() => {
      if (!callback) return;

      // 监听所有消息
      const unsubscribe = subscribe(null, null, callback);
      return unsubscribe;
   }, [subscribe, callback]);
};

// 默认导出
export default WebSocketContext;
