import { Stack, useLocalSearchParams } from 'expo-router';
import { useEffect, useMemo, useRef, useState } from 'react';
import {
  ActivityIndicator,
  Platform,
  Pressable,
  ScrollView,
  StyleSheet,
  TextInput,
  View,
} from 'react-native';

import { ThemedText } from '@/components/themed-text';
import { ThemedView } from '@/components/themed-view';
import { MaxContentWidth, Spacing } from '@/constants/theme';
import { useTheme } from '@/hooks/use-theme';
import { getRepo, type Transcript } from '@/lib/db';
import { downloadText } from '@/lib/download';
import { EXPORT_META, formatTranscript, type ExportFormat } from '@/lib/export';
import { formatClock } from '@/lib/format';
import type { Segment } from '@/lib/types';
import { useTranscribe } from '@/stores/transcribeStore';

export default function TranscriptScreen() {
  const theme = useTheme();
  const { id } = useLocalSearchParams<{ id: string }>();

  const [transcript, setTranscript] = useState<Transcript | null | undefined>(undefined);
  const [title, setTitle] = useState('');
  const [segments, setSegments] = useState<Segment[]>([]);
  const [dirty, setDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);

  // The just-transcribed audio is playable in-session (object URL on web).
  const audioUrl = useTranscribe((s) => (s.lastTranscriptId === id ? s.audioUrl : undefined));
  const audioRef = useRef<HTMLAudioElement | null>(null);

  useEffect(() => {
    let alive = true;
    void getRepo()
      .get(id)
      .then((t) => {
        if (!alive) return;
        setTranscript(t ?? null);
        setTitle(t?.title ?? '');
        setSegments(t?.segments ?? []);
      });
    return () => {
      alive = false;
    };
  }, [id]);

  // Web-only <audio> element for click-to-seek playback.
  useEffect(() => {
    if (Platform.OS !== 'web' || !audioUrl) return;
    const el = new Audio(audioUrl);
    audioRef.current = el;
    const onTime = () => setCurrentTime(el.currentTime);
    el.addEventListener('timeupdate', onTime);
    return () => {
      el.pause();
      el.removeEventListener('timeupdate', onTime);
      audioRef.current = null;
    };
  }, [audioUrl]);

  const activeIndex = useMemo(
    () => segments.findIndex((s) => currentTime >= s.start && currentTime < s.end),
    [segments, currentTime],
  );

  const seek = (t: number) => {
    const el = audioRef.current;
    if (!el) return;
    el.currentTime = t;
    void el.play();
  };

  const editSegment = (i: number, text: string) => {
    setSegments((prev) => prev.map((s, idx) => (idx === i ? { ...s, text } : s)));
    setDirty(true);
  };

  const save = async () => {
    setSaving(true);
    try {
      await getRepo().update(id, { title, segments });
      setDirty(false);
    } finally {
      setSaving(false);
    }
  };

  const onExport = (fmt: ExportFormat) => {
    const meta = EXPORT_META[fmt];
    const content = formatTranscript(segments, fmt, { title });
    const safeName = (title || 'transcript').replace(/[^\w.-]+/g, '_');
    downloadText(`${safeName}.${meta.ext}`, meta.mime, content);
  };

  if (transcript === undefined) return <Centered><ActivityIndicator /></Centered>;
  if (transcript === null)
    return (
      <Centered>
        <ThemedText type="small" themeColor="textSecondary">Transcript not found.</ThemedText>
      </Centered>
    );

  return (
    <ThemedView style={styles.fill}>
      <Stack.Screen options={{ title: title || 'Transcript' }} />
      <ScrollView contentContainerStyle={styles.content}>
        <TextInput
          value={title}
          onChangeText={(t) => {
            setTitle(t);
            setDirty(true);
          }}
          style={[styles.title, { color: theme.text }]}
          placeholder="Title"
          placeholderTextColor={theme.textSecondary}
        />

        {!audioUrl && (
          <ThemedText type="small" themeColor="textSecondary">
            Tip: audio playback is available right after transcribing. Re-import the file to scrub along.
          </ThemedText>
        )}

        <View style={styles.exportRow}>
          {(Object.keys(EXPORT_META) as ExportFormat[]).map((fmt) => (
            <Pressable
              key={fmt}
              onPress={() => onExport(fmt)}
              style={({ pressed }) => [styles.chip, { backgroundColor: theme.backgroundElement, opacity: pressed ? 0.7 : 1 }]}>
              <ThemedText type="small">{EXPORT_META[fmt].label}</ThemedText>
            </Pressable>
          ))}
        </View>

        {segments.map((s, i) => (
          <View key={i} style={[styles.segRow, i === activeIndex && { backgroundColor: theme.backgroundSelected }]}>
            <Pressable onPress={() => seek(s.start)} hitSlop={6}>
              <ThemedText type="code" themeColor="textSecondary" style={styles.ts}>
                {formatClock(s.start)}
              </ThemedText>
            </Pressable>
            <TextInput
              value={s.text}
              onChangeText={(t) => editSegment(i, t)}
              multiline
              style={[styles.segText, { color: theme.text }]}
            />
          </View>
        ))}

        {segments.length === 0 && (
          <ThemedText type="small" themeColor="textSecondary">This transcript has no segments.</ThemedText>
        )}
      </ScrollView>

      {dirty && (
        <Pressable
          onPress={() => void save()}
          disabled={saving}
          style={({ pressed }) => [styles.saveButton, { opacity: saving ? 0.6 : pressed ? 0.85 : 1 }]}>
          <ThemedText style={styles.saveText}>{saving ? 'Saving…' : 'Save changes'}</ThemedText>
        </Pressable>
      )}
    </ThemedView>
  );
}

function Centered({ children }: { children: React.ReactNode }) {
  return <ThemedView style={[styles.fill, styles.centered]}>{children}</ThemedView>;
}

const styles = StyleSheet.create({
  fill: { flex: 1 },
  centered: { alignItems: 'center', justifyContent: 'center' },
  content: { padding: Spacing.three, gap: Spacing.two, maxWidth: MaxContentWidth, width: '100%', alignSelf: 'center', paddingBottom: Spacing.six },
  title: { fontSize: 22, fontWeight: '700', paddingVertical: Spacing.two },
  exportRow: { flexDirection: 'row', flexWrap: 'wrap', gap: Spacing.two, marginBottom: Spacing.two },
  chip: { paddingHorizontal: Spacing.three, paddingVertical: Spacing.one, borderRadius: 999 },
  segRow: { flexDirection: 'row', gap: Spacing.two, paddingVertical: Spacing.one, paddingHorizontal: Spacing.two, borderRadius: Spacing.two, alignItems: 'flex-start' },
  ts: { paddingTop: 4, minWidth: 52 },
  segText: { flex: 1, fontSize: 16, lineHeight: 24, padding: 0 },
  saveButton: { position: 'absolute', bottom: Spacing.three, right: Spacing.three, left: Spacing.three, maxWidth: MaxContentWidth, alignSelf: 'center', backgroundColor: '#3c87f7', paddingVertical: Spacing.three, borderRadius: Spacing.three, alignItems: 'center' },
  saveText: { color: '#fff', fontWeight: '700' },
});
