/**
 * VoiceButton — Tap-to-Talk-Aufnahmeknopf (Streaming-Variante).
 *
 * Push-to-Talk gibt's nicht mehr. Tap startet Streaming-Aufnahme an die
 * Whisper-Bridge. Tap nochmal sendet stt_stream_end → Whisper liefert den
 * finalen Text → aria-bridge forwardet direkt an Brain. Keine dB/VAD-
 * Stille-Erkennung mehr — Whisper hoert auf semantische Stille (kein
 * neuer Text mehr).
 *
 * Diese Komponente ist absichtlich "dumm": sie kapselt nur den
 * Tap-Lifecycle + die Animation. Recording-Optionen (voice/speed/
 * location/interrupted) baut ChatScreen, die User-Bubble ebenfalls.
 *
 * Visuelles Feedback: pulsierende Animation + Dauer + dB-Pegel via
 * audioService.onMeterUpdate (das macht audio.ts noch fuer alte Records;
 * neu kommt der Pegel via NativeEventEmitter (PcmStreamMeter) — folgt).
 */

import React, { useState, useRef, useEffect, useCallback } from 'react';
import {
  View,
  Text,
  Animated,
  StyleSheet,
  Easing,
  TouchableOpacity,
} from 'react-native';
import audioService, { RecordingState } from '../services/audio';

// --- Typen ---

interface VoiceButtonProps {
  /** User hat getippt — ChatScreen soll Bubble bauen + startStreamingRecording.
   *  Returns true wenn die Aufnahme tatsaechlich gestartet ist. */
  onTapStart: () => Promise<boolean>;
  /** User hat nochmal getippt — ChatScreen soll stopStreamingRecording rufen. */
  onTapStop: () => Promise<void>;
  /** Button deaktivieren */
  disabled?: boolean;
  /** Wake-Word-Modus aktiv (zeigt gruenen Indikator-Dot) */
  wakeWordActive?: boolean;
}

// --- Komponente ---

const VoiceButton: React.FC<VoiceButtonProps> = ({
  onTapStart,
  onTapStop,
  disabled = false,
  wakeWordActive = false,
}) => {
  const [isRecording, setIsRecording] = useState(false);
  const [durationMs, setDurationMs] = useState(0);
  const [meterDb, setMeterDb] = useState(-160);
  const pulseAnim = useRef(new Animated.Value(1)).current;
  const durationTimer = useRef<ReturnType<typeof setInterval> | null>(null);

  // State via audioService.onStateChange spiegeln — der Service ist die
  // Quelle der Wahrheit (Streaming-Session, Wake-Word-Multi-Turn, etc.
  // koennen den Recording-State von extern aendern). isStreamingRecording
  // ist auch true wenn die Wake-Word-Konversation gerade aufzeichnet —
  // dann zeigt der Button "stop"-Symbol, und Tap stoppt die laufende
  // Aufnahme (egal ob via Wake-Word oder Knopf gestartet).
  useEffect(() => {
    const unsub = audioService.onStateChange((next: RecordingState) => {
      setIsRecording(next === 'recording');
    });
    // Initial-State synchronisieren
    setIsRecording(audioService.getRecordingState() === 'recording');
    return unsub;
  }, []);

  // Puls-Animation starten/stoppen
  useEffect(() => {
    if (isRecording) {
      const pulse = Animated.loop(
        Animated.sequence([
          Animated.timing(pulseAnim, {
            toValue: 1.2,
            duration: 600,
            easing: Easing.inOut(Easing.ease),
            useNativeDriver: true,
          }),
          Animated.timing(pulseAnim, {
            toValue: 1,
            duration: 600,
            easing: Easing.inOut(Easing.ease),
            useNativeDriver: true,
          }),
        ]),
      );
      pulse.start();
      return () => pulse.stop();
    } else {
      pulseAnim.setValue(1);
    }
  }, [isRecording, pulseAnim]);

  // Aufnahmedauer zaehlen + Metering (Pegel-Bar)
  useEffect(() => {
    if (isRecording) {
      setDurationMs(0);
      durationTimer.current = setInterval(() => {
        setDurationMs(prev => prev + 100);
      }, 100);
      const unsubMeter = audioService.onMeterUpdate(setMeterDb);
      return () => {
        unsubMeter();
        if (durationTimer.current) clearInterval(durationTimer.current);
      };
    } else {
      if (durationTimer.current) {
        clearInterval(durationTimer.current);
        durationTimer.current = null;
      }
      setMeterDb(-160);
    }
  }, [isRecording]);

  // Tap-Handler. Guard gegen Doppel-Tap waehrend asyncer Start/Stop.
  const tapBusy = useRef(false);
  const handleTap = useCallback(async () => {
    if (disabled || tapBusy.current) return;
    tapBusy.current = true;
    try {
      // Service-State fragen statt React-State (Closure koennte stale sein)
      const svcState = audioService.getRecordingState();
      if (svcState === 'recording') {
        await onTapStop();
      } else if (svcState === 'idle') {
        await onTapStart();
      }
      // 'processing': Stop laeuft gerade — nichts tun, User muss nochmal tippen
    } finally {
      tapBusy.current = false;
    }
  }, [disabled, onTapStart, onTapStop]);

  const formatDuration = (ms: number): string => {
    const seconds = Math.floor(ms / 1000);
    const tenths = Math.floor((ms % 1000) / 100);
    return `${seconds}.${tenths}s`;
  };

  // Meter-Visualisierung (-60..0 dB → 0..1). Bei Streaming-Mode liefert
  // audio.ts (noch) keinen Pegel, also bleibt der Balken leer — wird in
  // einem Folge-Commit nachgerueckt (PcmStreamRecorder-Module muss dafuer
  // einen RMS-Wert mit-emitten). Tut der Streaming-Funktion keinen Abbruch,
  // ist reines UI-Beiwerk.
  const meterLevel = Math.max(0, Math.min(1, (meterDb + 60) / 60));

  return (
    <View style={styles.container}>
      {wakeWordActive && !isRecording && (
        <View style={styles.wakeWordDot} />
      )}
      <Animated.View
        style={[
          styles.buttonOuter,
          isRecording && styles.buttonOuterRecording,
          { transform: [{ scale: pulseAnim }] },
        ]}
      >
        <TouchableOpacity
          activeOpacity={0.8}
          onPress={handleTap}
          disabled={disabled}
          style={[styles.buttonInner, isRecording && styles.buttonInnerRecording]}
        >
          <Text style={styles.buttonIcon}>{isRecording ? '⏹' : '🎙'}</Text>
        </TouchableOpacity>
      </Animated.View>
      {isRecording && (
        <View style={styles.infoRow}>
          <View style={[styles.meterBar, { width: `${meterLevel * 100}%` }]} />
          <Text style={styles.durationText}>{formatDuration(durationMs)}</Text>
        </View>
      )}
    </View>
  );
};

// --- Styles ---

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  wakeWordDot: {
    position: 'absolute',
    top: -4,
    right: -4,
    width: 10,
    height: 10,
    borderRadius: 5,
    backgroundColor: '#34C759',
    zIndex: 10,
  },
  buttonOuter: {
    width: 64,
    height: 64,
    borderRadius: 32,
    backgroundColor: 'rgba(0, 150, 255, 0.2)',
    alignItems: 'center',
    justifyContent: 'center',
  },
  buttonOuterRecording: {
    backgroundColor: 'rgba(255, 59, 48, 0.3)',
  },
  buttonInner: {
    width: 52,
    height: 52,
    borderRadius: 26,
    backgroundColor: '#0096FF',
    alignItems: 'center',
    justifyContent: 'center',
    elevation: 4,
    shadowColor: '#0096FF',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.4,
    shadowRadius: 4,
  },
  buttonInnerRecording: {
    backgroundColor: '#FF3B30',
  },
  buttonIcon: {
    fontSize: 24,
  },
  infoRow: {
    alignItems: 'center',
    marginTop: 4,
    width: 80,
  },
  meterBar: {
    height: 3,
    backgroundColor: '#FF3B30',
    borderRadius: 2,
    marginBottom: 2,
  },
  durationText: {
    color: '#FF3B30',
    fontSize: 12,
    fontVariant: ['tabular-nums'],
  },
});

export default VoiceButton;
