/**
 * AudioMeter.jsx — Audio level visualization with speech activity detection
 *
 * Features:
 *   - VU bar with color gradient (silent to loud)
 *   - Peak hold indicator with decay
 *   - Speech activity indicator from /social/speech/is_speaking
 *   - Real-time audio level visualization
 *   - Responsive design with audio metrics
 */

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

// Audio level thresholds and colors
const LEVEL_THRESHOLDS = [
  { max: 0.1, color: '#6b7280', label: 'Silent' },      // gray
  { max: 0.2, color: '#3b82f6', label: 'Low' },         // blue
  { max: 0.4, color: '#10b981', label: 'Moderate' },    // green
  { max: 0.6, color: '#f59e0b', label: 'Good' },        // amber
  { max: 0.8, color: '#f97316', label: 'Loud' },        // orange
  { max: 1.0, color: '#ef4444', label: 'Clipping' },    // red
];

function getColorForLevel(level) {
  for (const threshold of LEVEL_THRESHOLDS) {
    if (level <= threshold.max) {
      return threshold.color;
    }
  }
  return LEVEL_THRESHOLDS[LEVEL_THRESHOLDS.length - 1].color;
}

function getLabelForLevel(level) {
  for (const threshold of LEVEL_THRESHOLDS) {
    if (level <= threshold.max) {
      return threshold.label;
    }
  }
  return 'Clipping';
}

export function AudioMeter({ subscribe }) {
  const [audioLevel, setAudioLevel] = useState(0);
  const [peakLevel, setPeakLevel] = useState(0);
  const [isSpeaking, setIsSpeaking] = useState(false);
  const [audioStats, setAudioStats] = useState({
    avgLevel: 0,
    maxLevel: 0,
    peakHolds: 0,
  });

  const audioLevelRef = useRef(0);
  const peakLevelRef = useRef(0);
  const peakDecayRef = useRef(null);
  const audioStatsRef = useRef({
    levels: [],
    max: 0,
    peakHolds: 0,
  });

  // Subscribe to audio level topic
  useEffect(() => {
    const unsubAudio = subscribe(
      '/saltybot/audio_level',
      'std_msgs/Float32',
      (msg) => {
        if (typeof msg.data === 'number') {
          // Clamp and normalize level (0 to 1)
          const level = Math.max(0, Math.min(1, msg.data));
          audioLevelRef.current = level;
          setAudioLevel(level);

          // Update peak level
          if (level > peakLevelRef.current) {
            peakLevelRef.current = level;
            setPeakLevel(level);
            audioStatsRef.current.peakHolds++;

            // Reset peak decay timer
            if (peakDecayRef.current) {
              clearTimeout(peakDecayRef.current);
            }

            // Start decay after 1 second
            peakDecayRef.current = setTimeout(() => {
              let decayed = peakLevelRef.current - 0.05;
              const decayInterval = setInterval(() => {
                decayed -= 0.05;
                if (decayed <= audioLevelRef.current) {
                  peakLevelRef.current = audioLevelRef.current;
                  setPeakLevel(audioLevelRef.current);
                  clearInterval(decayInterval);
                } else {
                  peakLevelRef.current = decayed;
                  setPeakLevel(decayed);
                }
              }, 50);
            }, 1000);
          }

          // Track stats
          audioStatsRef.current.levels.push(level);
          if (audioStatsRef.current.levels.length > 100) {
            audioStatsRef.current.levels.shift();
          }
          audioStatsRef.current.max = Math.max(
            audioStatsRef.current.max,
            level
          );

          if (audioStatsRef.current.levels.length % 10 === 0) {
            const avg =
              audioStatsRef.current.levels.reduce((a, b) => a + b, 0) /
              audioStatsRef.current.levels.length;
            setAudioStats({
              avgLevel: avg,
              maxLevel: audioStatsRef.current.max,
              peakHolds: audioStatsRef.current.peakHolds,
            });
          }
        }
      }
    );

    return unsubAudio;
  }, [subscribe]);

  // Subscribe to speech activity
  useEffect(() => {
    const unsubSpeech = subscribe(
      '/social/speech/is_speaking',
      'std_msgs/Bool',
      (msg) => {
        setIsSpeaking(msg.data === true);
      }
    );

    return unsubSpeech;
  }, [subscribe]);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (peakDecayRef.current) {
        clearTimeout(peakDecayRef.current);
      }
    };
  }, []);

  const currentColor = getColorForLevel(audioLevel);
  const currentLabel = getLabelForLevel(audioLevel);
  const peakColor = getColorForLevel(peakLevel);

  return (
    <div className="space-y-4">
      {/* Speech Activity Indicator */}
      <div className="bg-gray-950 rounded-lg border border-cyan-950 p-4">
        <div className="flex items-center justify-between">
          <div className="text-cyan-700 text-xs font-bold tracking-widest">
            SPEECH ACTIVITY
          </div>
          <div className="flex items-center gap-2">
            <div
              className={`w-4 h-4 rounded-full transition-all ${
                isSpeaking ? 'bg-green-500 animate-pulse' : 'bg-gray-600'
              }`}
            />
            <span
              className={`text-sm font-semibold ${
                isSpeaking ? 'text-green-400' : 'text-gray-500'
              }`}
            >
              {isSpeaking ? 'SPEAKING' : 'SILENT'}
            </span>
          </div>
        </div>
      </div>

      {/* VU Meter */}
      <div className="bg-gray-950 rounded-lg border border-cyan-950 p-4 space-y-4">
        <div className="text-cyan-700 text-xs font-bold tracking-widest">
          AUDIO LEVEL
        </div>

        {/* Main VU Bar */}
        <div className="space-y-2">
          <div className="flex justify-between items-center">
            <span className="text-gray-400 text-sm">Level</span>
            <span className="text-xs font-mono" style={{ color: currentColor }}>
              {(audioLevel * 100).toFixed(1)}% {currentLabel}
            </span>
          </div>

          <div className="relative h-8 bg-gray-900 rounded border border-gray-800 overflow-hidden">
            {/* Level fill */}
            <div
              className="h-full transition-all duration-50 rounded"
              style={{
                width: `${audioLevel * 100}%`,
                backgroundColor: currentColor,
              }}
            />

            {/* Peak hold indicator */}
            <div
              className="absolute top-0 bottom-0 w-1 transition-all duration-100"
              style={{
                left: `${peakLevel * 100}%`,
                backgroundColor: peakColor,
                boxShadow: `0 0 8px ${peakColor}`,
              }}
            />

            {/* Grid markers */}
            <div className="absolute inset-0 flex">
              {[0.25, 0.5, 0.75].map((pos) => (
                <div
                  key={pos}
                  className="flex-1 border-r border-gray-700 opacity-30"
                  style={{ marginRight: '-1px' }}
                />
              ))}
            </div>
          </div>

          {/* Level scale labels */}
          <div className="flex justify-between text-xs text-gray-600">
            <span>0%</span>
            <span>25%</span>
            <span>50%</span>
            <span>75%</span>
            <span>100%</span>
          </div>
        </div>

        {/* Peak Hold Display */}
        <div className="flex items-center gap-2 pt-2 border-t border-gray-800">
          <span className="text-gray-500 text-xs">Peak Hold:</span>
          <div className="flex-1 h-6 bg-gray-900 rounded border border-gray-800 relative overflow-hidden">
            <div
              className="h-full transition-all duration-200 rounded"
              style={{
                width: `${peakLevel * 100}%`,
                backgroundColor: peakColor,
                opacity: 0.7,
              }}
            />
            <span className="absolute inset-0 flex items-center justify-center text-xs font-mono text-white">
              {(peakLevel * 100).toFixed(1)}%
            </span>
          </div>
        </div>
      </div>

      {/* Color Reference */}
      <div className="bg-gray-950 rounded-lg border border-cyan-950 p-4">
        <div className="text-cyan-700 text-xs font-bold tracking-widest mb-3">
          LEVEL REFERENCE
        </div>
        <div className="space-y-2">
          {LEVEL_THRESHOLDS.map((threshold) => (
            <div
              key={threshold.label}
              className="flex items-center gap-2"
            >
              <div
                className="w-4 h-4 rounded border border-gray-700"
                style={{ backgroundColor: threshold.color }}
              />
              <span className="text-xs text-gray-400">{threshold.label}</span>
              <span className="text-xs text-gray-600 ml-auto">
                {(threshold.max * 100).toFixed(0)}%
              </span>
            </div>
          ))}
        </div>
      </div>

      {/* Statistics */}
      <div className="bg-gray-950 rounded-lg border border-cyan-950 p-4">
        <div className="text-cyan-700 text-xs font-bold tracking-widest mb-3">
          STATISTICS
        </div>
        <div className="grid grid-cols-3 gap-3 text-center">
          <div>
            <div className="text-2xl font-mono text-cyan-400">
              {(audioStats.avgLevel * 100).toFixed(0)}%
            </div>
            <div className="text-xs text-gray-600 mt-1">Average Level</div>
          </div>
          <div>
            <div className="text-2xl font-mono text-yellow-400">
              {(audioStats.maxLevel * 100).toFixed(0)}%
            </div>
            <div className="text-xs text-gray-600 mt-1">Max Level</div>
          </div>
          <div>
            <div className="text-2xl font-mono text-green-400">
              {audioStats.peakHolds}
            </div>
            <div className="text-xs text-gray-600 mt-1">Peak Holds</div>
          </div>
        </div>
      </div>

      {/* Topic 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>Topics:</span>
          <span className="text-gray-500">
            /saltybot/audio_level, /social/speech/is_speaking
          </span>
        </div>
        <div className="flex justify-between">
          <span>Peak Decay:</span>
          <span className="text-gray-500">1s hold + 5% per 50ms</span>
        </div>
      </div>
    </div>
  );
}
