/**
 * BandwidthMonitor.jsx — ROS topic bandwidth monitor
 *
 * Features:
 *   - Tracks message rates for all subscribed ROS topics
 *   - Estimates bandwidth based on message size and frequency
 *   - Sortable table with topic name, rate, estimated size, and bandwidth
 *   - Sparkline mini-charts showing bandwidth over time
 *   - Total bandwidth summary
 *   - Auto-updates every 1 second
 */

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

const SPARKLINE_WIDTH = 60;
const SPARKLINE_HEIGHT = 20;
const MAX_HISTORY_POINTS = 30; // 30 seconds of data at 1Hz
const SAMPLE_INTERVAL = 1000; // 1 second

function estimateMessageSize(msg) {
  // Rough estimate of message size in bytes
  if (typeof msg === 'string') return msg.length;
  if (typeof msg === 'object') return JSON.stringify(msg).length;
  return 100; // Default estimate
}

function formatBandwidth(bytes) {
  if (bytes < 1024) return `${bytes.toFixed(1)} B/s`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB/s`;
  return `${(bytes / (1024 * 1024)).toFixed(3)} MB/s`;
}

function Sparkline({ data, width = SPARKLINE_WIDTH, height = SPARKLINE_HEIGHT }) {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas || data.length === 0) return;

    const ctx = canvas.getContext('2d');
    ctx.fillStyle = '#1f2937';
    ctx.fillRect(0, 0, width, height);

    if (data.length < 2) return;

    const max = Math.max(...data);
    const min = Math.min(...data);
    const range = max - min || 1;

    // Draw line
    ctx.strokeStyle = '#06b6d4';
    ctx.lineWidth = 1.5;
    ctx.beginPath();

    data.forEach((value, i) => {
      const x = (i / (data.length - 1)) * (width - 2) + 1;
      const y = height - ((value - min) / range) * (height - 2) - 1;

      if (i === 0) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    });

    ctx.stroke();

    // Draw area fill
    ctx.fillStyle = 'rgba(6, 182, 212, 0.2)';
    ctx.lineTo(width - 1, height);
    ctx.lineTo(1, height);
    ctx.closePath();
    ctx.fill();
  }, [data, width, height]);

  return <canvas ref={canvasRef} width={width} height={height} className="inline-block" />;
}

export function BandwidthMonitor() {
  const [topicStats, setTopicStats] = useState({});
  const [sortKey, setSortKey] = useState('bandwidth');
  const [sortAscending, setSortAscending] = useState(false);
  const statsRef = useRef({});
  const intervalRef = useRef(null);

  // Initialize bandwidth tracking
  useEffect(() => {
    // Sample bandwidth data every second
    intervalRef.current = setInterval(() => {
      const stats = {};
      let totalBandwidth = 0;

      Object.entries(statsRef.current).forEach(([topic, data]) => {
        const messageCount = data.messageCount || 0;
        const avgSize = data.totalSize > 0 ? data.totalSize / Math.max(1, messageCount) : 100;
        const bandwidth = messageCount * avgSize; // bytes per second

        stats[topic] = {
          messageCount,
          avgSize: avgSize.toFixed(1),
          bandwidth,
          bandwidthHistory: [
            ...(data.bandwidthHistory || []),
            bandwidth,
          ].slice(-MAX_HISTORY_POINTS),
          lastUpdate: Date.now(),
        };

        totalBandwidth += bandwidth;

        // Reset counters
        data.messageCount = 0;
        data.totalSize = 0;
      });

      setTopicStats({
        ...stats,
        __total: totalBandwidth,
      });
    }, SAMPLE_INTERVAL);

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

  // Expose tracking function for ROS bridge to use
  useEffect(() => {
    window.__trackRosMessage = (topic, message) => {
      if (!statsRef.current[topic]) {
        statsRef.current[topic] = {
          messageCount: 0,
          totalSize: 0,
          bandwidthHistory: [],
        };
      }

      statsRef.current[topic].messageCount++;
      statsRef.current[topic].totalSize += estimateMessageSize(message);
    };

    return () => {
      delete window.__trackRosMessage;
    };
  }, []);

  // Sort topics
  const sortedTopics = Object.entries(topicStats)
    .filter(([name]) => name !== '__total')
    .sort(([, a], [, b]) => {
      let aVal = a[sortKey];
      let bVal = b[sortKey];

      if (typeof aVal === 'string') {
        aVal = parseFloat(aVal);
        bVal = parseFloat(bVal);
      }

      return sortAscending ? aVal - bVal : bVal - aVal;
    });

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

  const totalBandwidth = topicStats.__total || 0;

  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">
            TOPIC BANDWIDTH MONITOR
          </div>
          <div className="text-gray-600 text-xs">
            {sortedTopics.length} topics tracked
          </div>
        </div>

        {/* Total bandwidth */}
        <div className="bg-gray-900 rounded border border-cyan-900 p-2 space-y-1">
          <div className="text-gray-600 text-xs">TOTAL BANDWIDTH</div>
          <div className="flex items-baseline gap-2">
            <span className="text-2xl font-mono text-cyan-400">
              {formatBandwidth(totalBandwidth)}
            </span>
            <span className="text-xs text-gray-700">
              (~{(totalBandwidth * 8).toFixed(0)} bits/s)
            </span>
          </div>
        </div>
      </div>

      {/* Table */}
      <div className="flex-1 bg-gray-950 rounded-lg border border-cyan-950 overflow-auto">
        {sortedTopics.length === 0 ? (
          <div className="flex items-center justify-center h-full text-gray-600">
            <div className="text-center">
              <div className="text-sm mb-2">No topics to monitor</div>
              <div className="text-xs text-gray-700">
                Topics will appear as they publish messages
              </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('topic')}
                >
                  Topic {sortKey === 'topic' && (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('messageCount')}
                >
                  Rate {sortKey === 'messageCount' && (sortAscending ? '▲' : '▼')}
                </th>
                <th
                  className="px-3 py-2 text-right font-bold text-green-400 cursor-pointer hover:bg-gray-800 whitespace-nowrap"
                  onClick={() => handleSort('avgSize')}
                >
                  Avg Size {sortKey === 'avgSize' && (sortAscending ? '▲' : '▼')}
                </th>
                <th
                  className="px-3 py-2 text-right font-bold text-yellow-400 cursor-pointer hover:bg-gray-800 whitespace-nowrap"
                  onClick={() => handleSort('bandwidth')}
                >
                  Bandwidth {sortKey === 'bandwidth' && (sortAscending ? '▲' : '▼')}
                </th>
                <th className="px-3 py-2 text-center font-bold text-teal-400 whitespace-nowrap">
                  Trend
                </th>
              </tr>
            </thead>
            <tbody>
              {sortedTopics.map(([topic, stats]) => (
                <tr
                  key={topic}
                  className="border-b border-gray-800 hover:bg-gray-900 transition-colors"
                >
                  <td className="px-3 py-2 text-cyan-300 font-mono truncate max-w-xs">
                    {topic}
                  </td>
                  <td className="px-3 py-2 text-right text-amber-300 font-mono">
                    {stats.messageCount} msg/s
                  </td>
                  <td className="px-3 py-2 text-right text-green-300 font-mono">
                    {stats.avgSize} B
                  </td>
                  <td className="px-3 py-2 text-right text-yellow-300 font-mono">
                    {formatBandwidth(stats.bandwidth)}
                  </td>
                  <td className="px-3 py-2 text-center">
                    {stats.bandwidthHistory && stats.bandwidthHistory.length > 0 ? (
                      <Sparkline data={stats.bandwidthHistory} />
                    ) : (
                      <span className="text-gray-600 text-xs">—</span>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      {/* 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>Update Interval:</span>
          <span className="text-gray-500">{SAMPLE_INTERVAL / 1000}s</span>
        </div>
        <div className="flex justify-between">
          <span>History Points:</span>
          <span className="text-gray-500">{MAX_HISTORY_POINTS} (30s window)</span>
        </div>
        <div className="flex justify-between">
          <span>Note:</span>
          <span className="text-gray-500">Message sizes are estimated from JSON serialization</span>
        </div>
      </div>
    </div>
  );
}
