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

export const SPEAKER_AUDIO_LEVEL_THRESHOLD = 5;
export const SPEAKER_FADE_IN_MS = 100;
export const SPEAKER_WAVES_FREEZE_DELAY_MS = 100;
export const SPEAKER_SILENCE_DEBOUNCE_MS = 500;
export const SPEAKER_FADE_OUT_MS = 300;

export type SpeakerTransitionMode = 'fadeIn' | 'fadeOut' | 'none';

export type SpeakingState = {
  isVisible: boolean;
  isWavesAnimating: boolean;
  transitionMode: SpeakerTransitionMode;
};

// Smooths the speaker indicator visibility so micro-pauses in speech do not
// flicker the badge. While speaking, the badge stays visible with running
// waves. On silence: waves collapse to their idle (min) height ~100ms later,
// badge stays visible for a 500ms debounce, then fades out over 300ms. If
// audio resumes during the debounce or fade-out, the timers are cancelled
// and the badge snaps back to the speaking state with no visible transition.
const useSpeakingState = (audioLevel: number): SpeakingState => {
  const [isVisible, setIsVisible] = useState(false);
  const [isWavesAnimating, setIsWavesAnimating] = useState(false);
  const [transitionMode, setTransitionMode] =
    useState<SpeakerTransitionMode>('none');

  const freezeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const fadeOutTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const isSpeakingRef = useRef(false);

  useEffect(() => {
    const clearAllTimers = () => {
      if (freezeTimerRef.current) {
        clearTimeout(freezeTimerRef.current);
        freezeTimerRef.current = null;
      }
      if (fadeOutTimerRef.current) {
        clearTimeout(fadeOutTimerRef.current);
        fadeOutTimerRef.current = null;
      }
      if (hideTimerRef.current) {
        clearTimeout(hideTimerRef.current);
        hideTimerRef.current = null;
      }
    };

    const speaking = audioLevel >= SPEAKER_AUDIO_LEVEL_THRESHOLD;

    if (speaking) {
      const hadPendingSilence =
        freezeTimerRef.current !== null ||
        fadeOutTimerRef.current !== null ||
        hideTimerRef.current !== null;
      clearAllTimers();

      if (hadPendingSilence) {
        isSpeakingRef.current = true;
        setTransitionMode('none');
        setIsVisible(true);
        setIsWavesAnimating(true);
      } else if (!isSpeakingRef.current) {
        isSpeakingRef.current = true;
        setTransitionMode('fadeIn');
        setIsVisible(true);
        setIsWavesAnimating(true);
      }
      return;
    }

    if (!isSpeakingRef.current) {
      return;
    }
    isSpeakingRef.current = false;

    freezeTimerRef.current = setTimeout(() => {
      freezeTimerRef.current = null;
      setIsWavesAnimating(false);
    }, SPEAKER_WAVES_FREEZE_DELAY_MS);

    fadeOutTimerRef.current = setTimeout(() => {
      fadeOutTimerRef.current = null;
      setTransitionMode('fadeOut');
      setIsVisible(false);
    }, SPEAKER_WAVES_FREEZE_DELAY_MS + SPEAKER_SILENCE_DEBOUNCE_MS);

    hideTimerRef.current = setTimeout(
      () => {
        hideTimerRef.current = null;
        setTransitionMode('none');
      },
      SPEAKER_WAVES_FREEZE_DELAY_MS +
        SPEAKER_SILENCE_DEBOUNCE_MS +
        SPEAKER_FADE_OUT_MS,
    );
  }, [audioLevel]);

  useEffect(() => {
    return () => {
      if (freezeTimerRef.current) clearTimeout(freezeTimerRef.current);
      if (fadeOutTimerRef.current) clearTimeout(fadeOutTimerRef.current);
      if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
    };
  }, []);

  return { isVisible, isWavesAnimating, transitionMode };
};

export default useSpeakingState;
