/**
 * VoiceButton - Push-to-Talk + Auto-Stop Aufnahmeknopf
 *
 * Zwei Modi:
 * 1. Push-to-Talk: gedrueckt halten zum Aufnehmen, loslassen zum Senden
 * 2. Tap-to-Talk: einmal tippen startet Aufnahme, VAD stoppt automatisch bei Stille
 *    (auch genutzt fuer Wake-Word-getriggerte Aufnahme)
 *
 * Visuelles Feedback durch pulsierende Animation waehrend der Aufnahme.
 */

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

// --- Typen ---

interface VoiceButtonProps {
  /** Wird aufgerufen wenn die Aufnahme fertig ist */
  onRecordingComplete: (result: RecordingResult) => void;
  /** Button deaktivieren */
  disabled?: boolean;
  /** Wake-Word-Modus aktiv (zeigt Indikator) */
  wakeWordActive?: boolean;
}

// --- Komponente ---

const VoiceButton: React.FC<VoiceButtonProps> = ({
  onRecordingComplete,
  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);
  const isLongPress = useRef(false);

  // 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
  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;
      }
    }
  }, [isRecording]);

  // VAD Silence Callback — Auto-Stop.
  // WICHTIG: NICHT auf isRecording prüfen (Closure ist stale) — stattdessen
  // audioService selber fragen. Empty deps → Listener wird EINMAL registriert.
  // audioService garantiert jetzt dass der Callback pro Aufnahme nur einmal
  // feuert (silenceFired-Latch).
  const onCompleteRef = useRef(onRecordingComplete);
  useEffect(() => { onCompleteRef.current = onRecordingComplete; }, [onRecordingComplete]);
  useEffect(() => {
    const unsubSilence = audioService.onSilenceDetected(async () => {
      if (audioService.getRecordingState() !== 'recording') return;
      const result = await audioService.stopRecording();
      setIsRecording(false);
      if (result && result.durationMs > 500) {
        onCompleteRef.current(result);
      }
    });
    return unsubSilence;
  }, []);

  // Auto-Start fuer Wake Word (extern getriggert)
  const startAutoRecording = useCallback(async () => {
    if (disabled || isRecording) return;
    const started = await audioService.startRecording(true); // autoStop = true
    if (started) {
      isLongPress.current = false;
      setIsRecording(true);
    }
  }, [disabled, isRecording]);

  // Push-to-Talk: Lang druecken
  const handlePressIn = async () => {
    if (disabled || isRecording) return;
    isLongPress.current = true;
    const started = await audioService.startRecording(false); // kein autoStop
    if (started) {
      setIsRecording(true);
    }
  };

  const handlePressOut = async () => {
    if (!isRecording || !isLongPress.current) return;
    isLongPress.current = false;
    setIsRecording(false);
    const result = await audioService.stopRecording();
    if (result && result.durationMs > 300) {
      onRecordingComplete(result);
    }
  };

  // Tap-to-Talk: Einmal tippen startet mit Auto-Stop.
  // Guard gegen Doppel-Tap während asyncer Start/Stop.
  const tapBusy = useRef(false);
  const handleTap = async () => {
    if (disabled || tapBusy.current) return;
    tapBusy.current = true;
    try {
      // Fragen WIR den Service, nicht den React-State (Closure kann stale sein)
      const svcState = audioService.getRecordingState();
      if (svcState === 'recording') {
        // Aufnahme manuell stoppen
        const result = await audioService.stopRecording();
        setIsRecording(false);
        if (result && result.durationMs > 300) {
          onRecordingComplete(result);
        }
      } else if (svcState === 'idle') {
        // Aufnahme mit Auto-Stop starten
        const started = await audioService.startRecording(true);
        if (started) {
          isLongPress.current = false;
          setIsRecording(true);
        }
      }
      // svcState === 'processing': Stopp in progress — nichts tun, User
      // muss nochmal tippen wenn fertig. Aber wir blockieren mit tapBusy
      // kurz damit der User's UI-Feedback synchron bleibt.
    } finally {
      tapBusy.current = false;
    }
  };

  // Expose startAutoRecording via ref fuer Wake Word
  React.useImperativeHandle(
    React.createRef(),
    () => ({ startAutoRecording }),
    [startAutoRecording],
  );

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

  // Meter-Visualisierung (0-1 Skala)
  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 }] },
        ]}
        onStartShouldSetResponder={() => true}
        onResponderGrant={handlePressIn}
        onResponderRelease={handlePressOut}
        onResponderTerminate={handlePressOut}
      >
        <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>
  );
};

// Expose startAutoRecording fuer externe Aufrufe (Wake Word)
export type VoiceButtonHandle = { startAutoRecording: () => Promise<void> };

// --- 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;
