import { useMemo, useState } from 'react';
import type { Transcript } from '@/api/types';

type Sentence = Transcript['paragraphs'][number]['sentences'][number];
type Word = Transcript['words'][number];

const CHUNK_SIZE = 9;

/** Split an array of words into fixed-size display chunks */
function chunkWords(words: Word[]): Word[][] {
  const chunks: Word[][] = [];
  for (let i = 0; i < words.length; i += CHUNK_SIZE) {
    chunks.push(words.slice(i, i + CHUNK_SIZE));
  }
  return chunks;
}

interface TranscriptOverlayProps {
  transcript: Transcript;
  activeSentence: Sentence | null;
  activeWordIndex: number | null;
  /** Center captions vertically (e.g. for audio-only playback) */
  centered?: boolean;
}

export function TranscriptOverlay({
  transcript,
  activeSentence,
  activeWordIndex,
  centered = false,
}: TranscriptOverlayProps) {
  const sentenceWords = useMemo(() => {
    if (!activeSentence) return [];
    return transcript.words.filter(
      (w) => w.start >= activeSentence.start && w.end <= activeSentence.end,
    );
  }, [transcript.words, activeSentence]);

  const chunks = useMemo(() => chunkWords(sentenceWords), [sentenceWords]);

  const activeWord =
    activeWordIndex !== null ? transcript.words[activeWordIndex] : null;

  // Remember the last spoken word so highlights hold during pauses.
  const [lastSpokenWord, setLastSpokenWord] = useState<Word | null>(null);
  if (activeWord && activeWord !== lastSpokenWord) {
    setLastSpokenWord(activeWord);
  }
  const highlightWord = activeWord ?? lastSpokenWord;

  // The chunk currently being spoken (null during a pause or if not found).
  const spokenChunk = useMemo(() => {
    if (!activeWord) return null;
    return (
      chunks.find((chunk) =>
        chunk.some(
          (w) => w.start === activeWord.start && w.end === activeWord.end,
        ),
      ) ?? null
    );
  }, [chunks, activeWord]);

  // Resolve which chunk to display: the spoken one, else hold the last one while
  // it's still part of the current sentence, else fall back to the first chunk.
  const [lastChunk, setLastChunk] = useState<Word[] | null>(null);
  let activeChunk: Word[] | null;
  if (spokenChunk) {
    activeChunk = spokenChunk;
  } else if (lastChunk && chunks.includes(lastChunk)) {
    activeChunk = lastChunk;
  } else {
    activeChunk = chunks[0] ?? null;
  }
  if (activeChunk !== lastChunk) {
    setLastChunk(activeChunk);
  }

  if (!activeSentence || !activeChunk || activeChunk.length === 0) return null;

  return (
    <div
      className={
        centered
          ? 'absolute inset-0 flex items-center justify-center px-6'
          : 'absolute bottom-15 left-0 right-0 flex justify-center px-6'
      }
    >
      <p className="rounded-lg px-5 py-3 text-2xl text-center max-w-lg">
        {activeChunk.map((word, i) => {
          const isSpoken =
            highlightWord !== null && word.start <= highlightWord.end;

          return (
            <span
              key={`${word.start}-${i}`}
              className={
                isSpoken
                  ? 'text-white font-medium transition-colors duration-150'
                  : 'text-white/40 transition-colors duration-150'
              }
            >
              {i > 0 ? ' ' : ''}
              {word.word}
            </span>
          );
        })}
      </p>
    </div>
  );
}
