import React, { useCallback, useEffect, useRef, useState } from "react";
import {
  Alert,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from "react-native";
import type { NativeStackScreenProps } from "@react-navigation/native-stack";
import { CharacterView } from "../components/CharacterView";
import { CharacterControls } from "../components/CharacterControls";
import { AudioVisualizer } from "../components/AudioVisualizer";
import { VOICE_LOOP } from "../config/constants";
import { useAudioRecorder } from "../hooks/useAudioRecorder";
import { useConversation } from "../hooks/useConversation";
import { useProductStore } from "../store/productStore";
import { useConversationStore } from "../store/conversationStore";
import { formatMs } from "../utils/formatters";
import { logger } from "../utils/logger";
import type { RootStackParamList } from "../navigation/types";
import type { RecordingResult } from "../types/Audio";
import type { AutoStopReason } from "../hooks/useAudioRecorder";

type Props = NativeStackScreenProps<RootStackParamList, "Conversation">;

export function ConversationScreen(_props: Props) {
  const product = useProductStore((s) => s.product);
  const setCharacterState = useConversationStore((s) => s.setCharacterState);
  const { isRecording, start, stop: stopRec } = useAudioRecorder();
  const {
    messages,
    characterState,
    lastLatency,
    sendAudio,
    stop: stopPlayback,
    ensureConversation,
  } = useConversation();

  const [busy, setBusy] = useState(false);
  const [handsFree, setHandsFree] = useState(false);

  const handsFreeRef = useRef(false);
  const processingRef = useRef(false);
  const mountedRef = useRef(true);
  const listenGenRef = useRef(0);

  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
      handsFreeRef.current = false;
      listenGenRef.current += 1;
    };
  }, []);

  useEffect(() => {
    ensureConversation().catch((e) => {
      Alert.alert("Error", e instanceof Error ? e.message : "No se pudo iniciar");
    });
  }, [ensureConversation]);

  const processTurnRef = useRef<(uri: string) => Promise<void>>(async () => {});
  const beginListeningRef = useRef<() => Promise<boolean>>(async () => false);

  const onAutoStop = useCallback(
    (result: RecordingResult | null, reason: AutoStopReason) => {
      if (!mountedRef.current || reason === "manual") return;

      if (!result) {
        if (handsFreeRef.current && reason === "no_speech") {
          setCharacterState("idle");
          setTimeout(() => {
            if (handsFreeRef.current && mountedRef.current) {
              void beginListeningRef.current();
            }
          }, 500);
        } else {
          setCharacterState("idle");
        }
        return;
      }

      void processTurnRef.current(result.uri);
    },
    [setCharacterState],
  );

  const beginListening = useCallback(async () => {
    if (!mountedRef.current || !handsFreeRef.current || processingRef.current) {
      return false;
    }
    const gen = ++listenGenRef.current;
    try {
      const started = await start({
        autoStopOnSilence: true,
        onAutoStop,
      });
      if (gen !== listenGenRef.current) return false;
      if (started) {
        setCharacterState("listening");
        return true;
      }
      setCharacterState("idle");
      return false;
    } catch (e) {
      logger.error("No se pudo abrir el micrófono", e);
      setCharacterState("idle");
      return false;
    }
  }, [onAutoStop, setCharacterState, start]);

  const processTurn = useCallback(
    async (uri: string) => {
      if (processingRef.current) return;
      processingRef.current = true;
      setBusy(true);
      setCharacterState("thinking");
      try {
        await sendAudio(uri);
        if (!mountedRef.current) return;

        // Liberar el turno ANTES de reabrir el mic; si no, beginListening
        // ve processingRef=true y no arranca el manos libres.
        processingRef.current = false;
        setBusy(false);

        if (handsFreeRef.current) {
          await new Promise((r) => setTimeout(r, VOICE_LOOP.postTtsDelayMs));
          if (mountedRef.current && handsFreeRef.current) {
            logger.info("TTS finished → reopening microphone");
            const ok = await beginListening();
            if (!ok) {
              logger.warn("No se pudo reabrir el micrófono tras el TTS");
              setCharacterState("idle");
            }
          }
        } else {
          setCharacterState("idle");
        }
      } catch (e) {
        if (mountedRef.current) {
          handsFreeRef.current = false;
          setHandsFree(false);
          setCharacterState("idle");
          Alert.alert(
            "Error",
            e instanceof Error ? e.message : "Falló la conversación",
          );
        }
      } finally {
        processingRef.current = false;
        if (mountedRef.current) setBusy(false);
      }
    },
    [beginListening, sendAudio, setCharacterState],
  );

  processTurnRef.current = processTurn;
  beginListeningRef.current = beginListening;

  const startHandsFree = useCallback(async () => {
    handsFreeRef.current = true;
    setHandsFree(true);
    const ok = await beginListening();
    if (!ok) {
      handsFreeRef.current = false;
      setHandsFree(false);
    }
  }, [beginListening]);

  const stopHandsFree = useCallback(async () => {
    handsFreeRef.current = false;
    setHandsFree(false);
    processingRef.current = false;
    listenGenRef.current += 1;
    await stopRec();
    await stopPlayback();
    setBusy(false);
    setCharacterState("idle");
  }, [setCharacterState, stopPlayback, stopRec]);

  if (!product) {
    return (
      <View style={styles.center}>
        <Text style={styles.muted}>No hay producto cargado</Text>
      </View>
    );
  }

  const onPressTalk = async () => {
    if (busy || processingRef.current) return;
    if (isRecording) {
      const result = await stopRec();
      if (!result) {
        setCharacterState("idle");
        return;
      }
      await processTurn(result.uri);
      return;
    }
    await startHandsFree();
  };

  const statusHint = isRecording
    ? "Escuchando… al callarte envío solo"
    : busy
      ? characterState === "talking"
        ? "Respondiendo…"
        : "Procesando tu mensaje…"
      : handsFree
        ? "Conversación activa — Detener para salir"
        : "Tocá Hablar para conversar manos libres";

  return (
    <View style={styles.container}>
      <CharacterView character={product.character} state={characterState} />
      <AudioVisualizer active={isRecording || characterState === "talking"} />

      <ScrollView style={styles.messages} contentContainerStyle={{ gap: 10 }}>
        {messages.map((m, idx) => (
          <View
            key={`${m.role}-${idx}`}
            style={[styles.bubble, m.role === "user" ? styles.user : styles.assistant]}
          >
            <Text style={styles.bubbleText}>{m.text}</Text>
          </View>
        ))}
      </ScrollView>

      {lastLatency ? (
        <Text style={styles.latency}>
          STT {formatMs(lastLatency.stt_ms)} · LLM {formatMs(lastLatency.llm_ms)} · TTS{" "}
          {formatMs(lastLatency.tts_ms)}
        </Text>
      ) : null}

      <CharacterControls
        onTalk={onPressTalk}
        onStop={stopHandsFree}
        isRecording={isRecording}
        isBusy={busy && !isRecording}
        talkLabel={isRecording ? "Enviar ahora" : busy ? "Esperá…" : "Hablar"}
        stopLabel="Detener"
      />

      <Pressable onPress={stopHandsFree} style={styles.hintWrap}>
        <Text style={styles.hint}>{statusHint}</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, gap: 16 },
  center: { flex: 1, alignItems: "center", justifyContent: "center" },
  muted: { color: "#B8AFA0" },
  messages: { flex: 1 },
  bubble: {
    padding: 12,
    borderRadius: 14,
    maxWidth: "90%",
  },
  user: {
    alignSelf: "flex-end",
    backgroundColor: "#2A2218",
  },
  assistant: {
    alignSelf: "flex-start",
    backgroundColor: "#3A2E1E",
    borderWidth: 1,
    borderColor: "#C4A35A55",
  },
  bubbleText: { color: "#FFF8EC", lineHeight: 20 },
  latency: { color: "#6E6658", fontSize: 11, textAlign: "center" },
  hintWrap: { alignItems: "center" },
  hint: { color: "#8E8574", fontSize: 12, textAlign: "center" },
});
