/**
 * Sample screen — paragraph + Play / Pause / Stop + per-word highlight (expo-speech).
 *
 * Setup:
 *   npx expo install expo-speech
 * @expo/vector-icons ships with Expo (Ionicons).
 *
 * Expo Router: save as `app/listen-aloud.tsx` or import into your stack.
 */

import { Ionicons } from "@expo/vector-icons";
import * as Speech from "expo-speech";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
  Platform,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

/** Demo paragraph (trimmed for TTS and UI). */
const PARAGRAPH =
  "Reading aloud helps you catch awkward phrasing and makes content accessible when your eyes are busy. " +
  "This screen uses the device text-to-speech engine through expo-speech. " +
  "Tap play to start listening, pause to hold your place on iOS and the web, and stop to end playback and clear highlighting. " +
  "On Android, pause is not available from the OS API used here, so the pause control stops speech; tap play to start again from the beginning.";

type ReadableWordSeg = { word: string; sep: string; start: number };

function segmentReadableWords(text: string): ReadableWordSeg[] {
  const out: ReadableWordSeg[] = [];
  const re = /(\S+)(\s*)/g;
  let m: RegExpExecArray | null;
  while ((m = re.exec(text)) !== null) {
    out.push({ word: m[1], sep: m[2], start: m.index });
  }
  return out;
}

function wordIndexFromBoundaryCharIndex(text: string, charIndex: number): number {
  const segs = segmentReadableWords(text);
  if (segs.length === 0) return 0;
  const idx = Math.max(0, Math.min(charIndex, Math.max(0, text.length - 1)));
  for (let i = 0; i < segs.length; i++) {
    const { start, word } = segs[i];
    if (idx >= start && idx < start + word.length) return i;
  }
  for (let i = 0; i < segs.length - 1; i++) {
    const gapStart = segs[i].start + segs[i].word.length;
    const gapEnd = segs[i + 1].start;
    if (idx >= gapStart && idx < gapEnd) return i + 1;
  }
  return segs.length - 1;
}

function readBoundaryCharIndex(ev: unknown): number {
  if (
    ev &&
    typeof ev === "object" &&
    "charIndex" in ev &&
    typeof (ev as { charIndex: unknown }).charIndex === "number"
  ) {
    return (ev as { charIndex: number }).charIndex;
  }
  return 0;
}

type Phase = "idle" | "speaking" | "paused";

export default function ListenAloudScreen() {
  const colorScheme = useColorScheme();
  const isDark = colorScheme === "dark";
  const theme = isDark ? colors.dark : colors.light;

  const textTrimmed = useMemo(() => PARAGRAPH.trim(), []);
  const wordSegments = useMemo(() => segmentReadableWords(textTrimmed), [textTrimmed]);

  const [phase, setPhase] = useState<Phase>("idle");
  const [highlightIndex, setHighlightIndex] = useState<number | null>(null);

  const resetUi = useCallback(() => {
    setPhase("idle");
    setHighlightIndex(null);
  }, []);

  useEffect(() => {
    return () => {
      void Speech.stop();
    };
  }, []);

  const speakFromStart = useCallback(() => {
    void Speech.stop();
    setPhase("speaking");
    setHighlightIndex(0);

    Speech.speak(textTrimmed, {
      language: "en-US",
      pitch: 1,
      rate: 0.96,
      onStart: () => setHighlightIndex(0),
      onBoundary: (ev: unknown) => {
        const ci = readBoundaryCharIndex(ev);
        setHighlightIndex(wordIndexFromBoundaryCharIndex(textTrimmed, ci));
      },
      onDone: resetUi,
      onStopped: resetUi,
      onError: resetUi,
    });
  }, [resetUi, textTrimmed]);

  const handlePlay = useCallback(async () => {
    if (phase === "paused" && Platform.OS !== "android") {
      await Speech.resume();
      setPhase("speaking");
      return;
    }
    speakFromStart();
  }, [phase, speakFromStart]);

  const handlePause = useCallback(async () => {
    if (phase !== "speaking") return;
    if (Platform.OS === "android") {
      await Speech.stop();
      resetUi();
      return;
    }
    await Speech.pause();
    setPhase("paused");
  }, [phase, resetUi]);

  const handleStop = useCallback(async () => {
    await Speech.stop();
    resetUi();
  }, [resetUi]);

  const playDisabled = phase === "speaking";
  const pauseDisabled = phase !== "speaking";
  const stopDisabled = phase === "idle";

  return (
    <SafeAreaView style={[styles.screen, { backgroundColor: theme.bg }]}>
      <ScrollView
        contentContainerStyle={styles.scrollContent}
        showsVerticalScrollIndicator={false}
      >
        <Text style={[styles.title, { color: theme.text }]}>Listen aloud</Text>
        <Text style={[styles.subtitle, { color: theme.muted }]}>
          Word highlight follows playback when the engine reports boundaries.
        </Text>

        <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>
          <Text style={[styles.cardLabel, { color: theme.muted }]}>Paragraph</Text>
          <Text style={[styles.paragraph, { color: theme.text }]}>
            {wordSegments.map((seg, i) => (
              <Text
                key={`${seg.start}-${i}`}
                style={
                  (phase === "speaking" || phase === "paused") && highlightIndex === i
                    ? [styles.wordHi, { backgroundColor: theme.highlightBg, color: theme.highlightText }]
                    : undefined
                }
              >
                {seg.word}
                {seg.sep}
              </Text>
            ))}
          </Text>
        </View>

        <View style={styles.toolbar}>
          <Pressable
            onPress={() => void handlePlay()}
            disabled={playDisabled}
            style={({ pressed }) => [
              styles.btn,
              styles.btnPrimary,
              { backgroundColor: theme.primary, opacity: playDisabled ? 0.45 : 1 },
              pressed && !playDisabled && styles.btnPressed,
            ]}
            accessibilityRole="button"
            accessibilityLabel="Play or resume"
          >
            <Ionicons name="play" size={22} color="#fff" />
            <Text style={styles.btnLabel}>Play</Text>
          </Pressable>

          <Pressable
            onPress={() => void handlePause()}
            disabled={pauseDisabled}
            style={({ pressed }) => [
              styles.btn,
              styles.btnSecondary,
              {
                backgroundColor: theme.secondary,
                borderColor: theme.border,
                opacity: pauseDisabled ? 0.45 : 1,
              },
              pressed && !pauseDisabled && styles.btnPressed,
            ]}
            accessibilityRole="button"
            accessibilityLabel={Platform.OS === "android" ? "Pause (stops on Android)" : "Pause"}
          >
            <Ionicons name="pause" size={22} color={theme.text} />
            <Text style={[styles.btnLabel, { color: theme.text }]}>
              {Platform.OS === "android" ? "Pause" : "Pause"}
            </Text>
          </Pressable>

          <Pressable
            onPress={() => void handleStop()}
            disabled={stopDisabled}
            style={({ pressed }) => [
              styles.btn,
              styles.btnSecondary,
              {
                backgroundColor: theme.secondary,
                borderColor: theme.border,
                opacity: stopDisabled ? 0.45 : 1,
              },
              pressed && !stopDisabled && styles.btnPressed,
            ]}
            accessibilityRole="button"
            accessibilityLabel="Stop"
          >
            <Ionicons name="stop" size={22} color={theme.text} />
            <Text style={[styles.btnLabel, { color: theme.text }]}>Stop</Text>
          </Pressable>
        </View>

        <Text style={[styles.footnote, { color: theme.muted }]}>
          Requires expo-speech. Physical iOS devices need silent mode off for audio.
        </Text>
      </ScrollView>
    </SafeAreaView>
  );
}

const colors = {
  light: {
    bg: "#f4f4f5",
    card: "#ffffff",
    border: "#e4e4e7",
    text: "#18181b",
    muted: "#71717a",
    primary: "#7c3aed",
    secondary: "#fafafa",
    highlightBg: "#ddd6fe",
    highlightText: "#3b0764",
  },
  dark: {
    bg: "#09090b",
    card: "#18181b",
    border: "#27272a",
    text: "#fafafa",
    muted: "#a1a1aa",
    primary: "#8b5cf6",
    secondary: "#27272a",
    highlightBg: "#4c1d95",
    highlightText: "#ede9fe",
  },
};

const styles = StyleSheet.create({
  screen: {
    flex: 1,
  },
  scrollContent: {
    paddingHorizontal: 20,
    paddingTop: 24,
    paddingBottom: 40,
  },
  title: {
    fontSize: 28,
    fontWeight: "700",
    letterSpacing: -0.5,
  },
  subtitle: {
    marginTop: 8,
    fontSize: 15,
    lineHeight: 22,
  },
  card: {
    marginTop: 24,
    padding: 20,
    borderRadius: 16,
    borderWidth: 1,
  },
  cardLabel: {
    fontSize: 12,
    fontWeight: "600",
    textTransform: "uppercase",
    letterSpacing: 0.6,
    marginBottom: 12,
  },
  paragraph: {
    fontSize: 18,
    lineHeight: 30,
  },
  wordHi: {
    borderRadius: 6,
    fontWeight: "700",
    overflow: "hidden",
  },
  toolbar: {
    flexDirection: "row",
    flexWrap: "wrap",
    gap: 12,
    marginTop: 28,
  },
  btn: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "center",
    gap: 8,
    paddingVertical: 14,
    paddingHorizontal: 20,
    borderRadius: 14,
    minWidth: 108,
  },
  btnPrimary: {},
  btnSecondary: {
    borderWidth: 1,
  },
  btnPressed: {
    opacity: 0.88,
    transform: [{ scale: 0.98 }],
  },
  btnLabel: {
    fontSize: 16,
    fontWeight: "600",
    color: "#fff",
  },
  footnote: {
    marginTop: 24,
    fontSize: 13,
    lineHeight: 18,
  },
});
