/**
 * NodeList.jsx — ROS node enumeration and status monitor
 *
 * Features:
 *   - Enumerate active ROS nodes from rosbridge
 *   - Real-time node status tracking (alive/dead based on heartbeat)
 *   - Display node name, status, and topic subscriptions
 *   - Color-coded status indicators (green=alive, gray=dead)
 *   - Sortable table with node statistics
 *   - Track last update time for each node
 */

import { useEffect, useRef, useState } from 'react';

const HEARTBEAT_TIMEOUT = 5000; // 5 seconds without update = dead
const POLL_INTERVAL = 2000; // Check node status every 2 seconds

function formatTimestamp(timestamp) {
  const date = new Date(timestamp);
  return date.toLocaleTimeString('en-US', {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
  });
}

function getNodeStatus(lastUpdate) {
  const now = Date.now();
  return now - lastUpdate < HEARTBEAT_TIMEOUT ? 'alive' : 'dead';
}

export function NodeList({ subscribe, publish, callService }) {
  const [nodeData, setNodeData] = useState({});
  const [sortKey, setSortKey] = useState('name');
  const [sortAscending, setSortAscending] = useState(true);
  const nodeRefRef = useRef({});
  const pollIntervalRef = useRef(null);

  // Track node activity via topic subscriptions
  useEffect(() => {
    // Subscribe to /rosout to track active nodes
    const unsubscribe = subscribe(
      '/rosout',
      'rcl_interfaces/Log',
      (msg) => {
        try {
          const nodeName = msg.name || 'unknown';

          if (!nodeRefRef.current[nodeName]) {
            nodeRefRef.current[nodeName] = {
              name: nodeName,
              topicCount: 0,
              firstSeen: Date.now(),
              lastUpdate: Date.now(),
            };
          } else {
            nodeRefRef.current[nodeName].lastUpdate = Date.now();
          }
        } catch (e) {
          console.error('Error tracking node:', e);
        }
      }
    );

    return unsubscribe;
  }, [subscribe]);

  // Update node status periodically
  useEffect(() => {
    pollIntervalRef.current = setInterval(() => {
      const nodes = {};
      const now = Date.now();

      Object.entries(nodeRefRef.current).forEach(([name, data]) => {
        const status = getNodeStatus(data.lastUpdate);
        const uptime = ((now - data.firstSeen) / 1000).toFixed(1);

        nodes[name] = {
          name,
          status,
          topicCount: data.topicCount || 0,
          lastUpdate: data.lastUpdate,
          uptime: parseFloat(uptime),
          lastSeen: formatTimestamp(data.lastUpdate),
        };
      });

      setNodeData(nodes);
    }, POLL_INTERVAL);

    return () => clearInterval(pollIntervalRef.current);
  }, []);

  // Sort nodes
  const sortedNodes = Object.values(nodeData).sort((a, b) => {
    let aVal = a[sortKey];
    let bVal = b[sortKey];

    // Handle string comparison for name
    if (typeof aVal === 'string' && typeof bVal === 'string') {
      return sortAscending ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
    }

    // Handle numeric comparison
    return sortAscending ? aVal - bVal : bVal - aVal;
  });

  const handleSort = (key) => {
    if (sortKey === key) {
      setSortAscending(!sortAscending);
    } else {
      setSortKey(key);
      setSortAscending(true);
    }
  };

  const aliveCount = sortedNodes.filter((n) => n.status === 'alive').length;
  const deadCount = sortedNodes.filter((n) => n.status === 'dead').length;

  return (
    <div className="flex flex-col h-full space-y-3">
      {/* Summary */}
      <div className="bg-gray-950 rounded-lg border border-cyan-950 p-3 space-y-2">
        <div className="flex justify-between items-center">
          <div className="text-cyan-700 text-xs font-bold tracking-widest">
            ROS NODE MONITOR
          </div>
          <div className="text-gray-600 text-xs">
            {sortedNodes.length} total nodes
          </div>
        </div>

        {/* Node status summary */}
        <div className="grid grid-cols-2 gap-2">
          <div className="bg-gray-900 rounded p-2">
            <div className="flex items-center gap-2">
              <div className="w-2 h-2 rounded-full bg-green-500" />
              <span className="text-gray-600 text-xs">Alive</span>
              <span className="text-green-400 font-mono text-sm font-bold">{aliveCount}</span>
            </div>
          </div>
          <div className="bg-gray-900 rounded p-2">
            <div className="flex items-center gap-2">
              <div className="w-2 h-2 rounded-full bg-gray-500" />
              <span className="text-gray-600 text-xs">Dead</span>
              <span className="text-gray-400 font-mono text-sm font-bold">{deadCount}</span>
            </div>
          </div>
        </div>
      </div>

      {/* Node table */}
      <div className="flex-1 bg-gray-950 rounded-lg border border-cyan-950 overflow-auto">
        {sortedNodes.length === 0 ? (
          <div className="flex items-center justify-center h-full text-gray-600">
            <div className="text-center">
              <div className="text-sm mb-2">Waiting for ROS activity</div>
              <div className="text-xs text-gray-700">
                Nodes will appear as they publish to /rosout
              </div>
            </div>
          </div>
        ) : (
          <table className="w-full text-xs border-collapse">
            <thead className="sticky top-0 bg-gray-900 border-b border-gray-800">
              <tr>
                <th
                  className="px-3 py-2 text-left font-bold text-cyan-400 cursor-pointer hover:bg-gray-800"
                  onClick={() => handleSort('name')}
                >
                  Node Name {sortKey === 'name' && (sortAscending ? '▲' : '▼')}
                </th>
                <th
                  className="px-3 py-2 text-center font-bold text-green-400 cursor-pointer hover:bg-gray-800 whitespace-nowrap"
                  onClick={() => handleSort('status')}
                >
                  Status {sortKey === 'status' && (sortAscending ? '▲' : '▼')}
                </th>
                <th
                  className="px-3 py-2 text-right font-bold text-amber-400 cursor-pointer hover:bg-gray-800 whitespace-nowrap"
                  onClick={() => handleSort('uptime')}
                >
                  Uptime (s) {sortKey === 'uptime' && (sortAscending ? '▲' : '▼')}
                </th>
                <th className="px-3 py-2 text-right font-bold text-teal-400 whitespace-nowrap">
                  Last Seen
                </th>
              </tr>
            </thead>
            <tbody>
              {sortedNodes.map((node) => (
                <tr
                  key={node.name}
                  className={`border-b border-gray-800 hover:bg-gray-900 transition-colors ${
                    node.status === 'dead' ? 'opacity-60' : ''
                  }`}
                >
                  <td className="px-3 py-2 text-cyan-300 font-mono truncate max-w-sm">
                    {node.name}
                  </td>
                  <td className="px-3 py-2 text-center">
                    <div className="flex items-center justify-center gap-2">
                      <div
                        className={`w-2 h-2 rounded-full ${
                          node.status === 'alive' ? 'bg-green-500' : 'bg-gray-500'
                        }`}
                      />
                      <span
                        className={
                          node.status === 'alive'
                            ? 'text-green-300 font-bold'
                            : 'text-gray-400'
                        }
                      >
                        {node.status.toUpperCase()}
                      </span>
                    </div>
                  </td>
                  <td className="px-3 py-2 text-right text-amber-300 font-mono">
                    {node.uptime}
                  </td>
                  <td className="px-3 py-2 text-right text-gray-500 font-mono text-xs">
                    {node.lastSeen}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      {/* Configuration info */}
      <div className="bg-gray-950 rounded border border-gray-800 p-2 text-xs text-gray-600 space-y-1">
        <div className="flex justify-between">
          <span>Topic Source:</span>
          <span className="text-gray-500">/rosout (rcl_interfaces/Log)</span>
        </div>
        <div className="flex justify-between">
          <span>Heartbeat Timeout:</span>
          <span className="text-gray-500">{HEARTBEAT_TIMEOUT / 1000}s</span>
        </div>
        <div className="flex justify-between">
          <span>Status Check Interval:</span>
          <span className="text-gray-500">{POLL_INTERVAL / 1000}s</span>
        </div>
        <div className="flex justify-between">
          <span>Note:</span>
          <span className="text-gray-500">
            Nodes detected via /rosout activity; inactive nodes marked as dead after timeout
          </span>
        </div>
      </div>
    </div>
  );
}
