import Voice from "@react-native-voice/voice";
import { router, useFocusEffect } from "expo-router";
import { useCallback, useEffect, useRef, useState } from "react";
import Svg, { Path } from "react-native-svg";
import {
  ActivityIndicator,
  Alert,
  KeyboardAvoidingView,
  NativeModules,
  Platform,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from "react-native";
import { loadRecorderSettings } from "@/lib/recorder-settings";
import { getStrings, type Locale, t } from "@/lib/translations";

function formatDuration(durationMs: number) {
  const totalSeconds = Math.floor(durationMs / 1000);
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;

  return `${minutes.toString().padStart(2, "0")}:${seconds
    .toString()
    .padStart(2, "0")}`;
}

export default function RecorderScreen() {
  const [backendUrl, setBackendUrl] = useState("");
  const [authToken, setAuthToken] = useState("");
  const [locale, setLocale] = useState<Locale>("ca");
  const [strings, setStrings] = useState(() => getStrings("ca"));

  const [transcript, setTranscript] = useState("");
  const [interimTranscript, setInterimTranscript] = useState("");
  const [statusMessage, setStatusMessage] = useState("");
  const [responsePreview, setResponsePreview] = useState("");
  const [isSending, setIsSending] = useState(false);
  const [isHolding, setIsHolding] = useState(false);
  const [listeningMs, setListeningMs] = useState(0);
  const startRef = useRef<number>(0);
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const listeningActiveRef = useRef(false);

  const refreshSettings = useCallback(() => {
    let isMounted = true;

    async function loadStoredValues() {
      try {
        const settings = await loadRecorderSettings();

        if (!isMounted) {
          return;
        }

        setBackendUrl(settings.backendUrl);
        setAuthToken(settings.authToken);
        setLocale(settings.language);
        setStrings(getStrings(settings.language));
      } catch {
        if (isMounted) {
          setStatusMessage(strings.loadError);
        }
      }
    }

    void loadStoredValues();

    return () => {
      isMounted = false;
    };
  }, []);

  useFocusEffect(refreshSettings);

  useEffect(() => {
    if (Platform.OS === "web" || !NativeModules.Voice) {
      return;
    }

    Voice.onSpeechStart = (e) => {
      console.log("Voice.onSpeechStart", e);
      setTranscript("");
      setInterimTranscript("");
      setStatusMessage(strings.recording);
      startRef.current = Date.now();
      timerRef.current = setInterval(() => {
        const elapsed = Date.now() - startRef.current;
        setListeningMs(elapsed);
      }, 250);
    };

    Voice.onSpeechEnd = (e) => {
      console.log("Voice.onSpeechEnd", e);
      listeningActiveRef.current = false;
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }
    };

    Voice.onSpeechResults = (e) => {
      console.log("Voice.onSpeechResults", e);
      const values = (e as unknown as { value: string[] }).value;
      if (values && values.length > 0) {
        const last = values[values.length - 1];
        setTranscript(last);
      }
    };

    Voice.onSpeechPartialResults = (e) => {
      console.log("Voice.onSpeechPartialResults", e);
      const values = (e as unknown as { value: string[] }).value;
      if (values && values.length > 0) {
        const last = values[values.length - 1];
        setInterimTranscript(last || "");
      }
    };

    Voice.onSpeechError = (e) => {
      console.log("Voice.onSpeechError", e);
      const message = (e as unknown as { error?: { message: string } }).error?.message || "Speech recognition error";
      setStatusMessage(message);
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }
      setListeningMs(0);
      listeningActiveRef.current = false;
      Alert.alert(strings.recordingFailedTitle, message);
    };

    return () => {
      Voice.removeAllListeners();
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }
    };
  }, []);

  useEffect(() => {
    return () => {
      if (listeningActiveRef.current && Platform.OS !== "web" && NativeModules.Voice) {
        Voice.stop().catch(() => undefined);
        listeningActiveRef.current = false;
      }
    };
  }, []);

  async function startListening() {
    try {
      setResponsePreview("");
      setTranscript("");
      setInterimTranscript("");
      const localeCode =
        locale.includes("ca")
          ? "ca-ES"
          : locale.includes("es")
            ? "es-ES"
            : "en-US";
      setIsHolding(true);
      if (Platform.OS === "web") {
        console.log("Voice not available on web");
        Alert.alert("Not supported", "Speech recognition is only available on mobile devices. Open the app on Android or iOS.");
        setIsHolding(false);
        return;
      }
      if (!NativeModules.Voice) {
        Alert.alert("Not supported", "Speech recognition module not found. Make sure the app is built with native modules.");
        setIsHolding(false);
        return;
      }
      await Voice.start(localeCode);
      listeningActiveRef.current = true;
    } catch (error) {
      const msg = error instanceof Error ? error.message : "Failed to start speech recognition";
      console.error("Voice.start failed:", error);
      Alert.alert(strings.recordingFailedTitle, msg);
    }
  }

  async function stopListeningAndSend() {
    setIsHolding(false);
    const wasListening = listeningActiveRef.current;
    if (!wasListening) {
      setStatusMessage(transcript ? strings.voiceMessageSent : strings.readyToRecord);
      return;
    }
    listeningActiveRef.current = false;
    if (Platform.OS === "web") {
      const finalText = (transcript + " " + interimTranscript).trim().replace(/\s+/g, " ");
      if (finalText) {
        await sendCommand(finalText);
      } else {
        setStatusMessage(strings.readyToRecord);
      }
      return;
    }
    try {
      await Voice.stop();

      const finalText = (transcript + " " + interimTranscript).trim().replace(/\s+/g, " ");

      if (!finalText) {
        setStatusMessage(strings.readyToRecord);
        return;
      }

      await sendCommand(finalText);
    } catch (error) {
      listeningActiveRef.current = false;
      const msg = error instanceof Error ? error.message : "Stop failed";
      console.error("Voice.stop failed:", error);
      setStatusMessage(msg);
    }
  }

  async function sendCommand(text: string) {
    const trimmedUrl = backendUrl.trim().replace(/\/+$/, "");
    const commandUrl = trimmedUrl.endsWith("/commands")
      ? `${trimmedUrl}/text`
      : `${trimmedUrl}/commands/text`;

    if (!commandUrl) {
      setStatusMessage(strings.noBackendUrl);
      return;
    }

    try {
      setIsSending(true);
      setStatusMessage(strings.uploadingRecording);

      const headers: Record<string, string> = {
        "Content-Type": "application/json",
      };

      if (authToken.trim()) {
        headers.Authorization = `Bearer ${authToken.trim()}`;
      }

      const response = await fetch(commandUrl, {
        method: "POST",
        headers,
        body: JSON.stringify({ text }),
      });

      const responseText = await response.text();
      setResponsePreview(responseText.slice(0, 400));
      setTranscript("");
      setInterimTranscript("");

      if (!response.ok) {
        throw new Error(`${response.status}. ${responseText}`);
      }

      setStatusMessage(strings.voiceMessageSent);
    } catch (error) {
      setStatusMessage(strings.uploadFailed);
      Alert.alert(
        strings.uploadFailed,
        error instanceof Error ? error.message : "",
      );
    } finally {
      setIsSending(false);
    }
  }

  async function handlePressIn() {
    if (isSending) return;
    await startListening();
  }

  async function handlePressOut() {
    await stopListeningAndSend();
  }

  const releaseLabel = t("releaseToStop", locale);
  const holdLabel = t("holdToRecord", locale);
  const openSettingsHint = t("openSettingsHint", locale);
  const appTitleLabel = t("appTitle", locale);
  const recorderTitleLabel = t("recorderTitle", locale);
  const serverResponseLabel = t("serverResponse", locale);

  const displayText = interimTranscript || transcript;

  return (
    <View style={styles.safeArea}>
      <KeyboardAvoidingView
        style={styles.keyboardAvoidingView}
        behavior={Platform.OS === "ios" ? "padding" : undefined}
      >
        <ScrollView
          style={styles.scrollView}
          contentContainerStyle={styles.content}
          keyboardShouldPersistTaps="handled"
        >
          <View style={styles.hero}>
            <View style={styles.heroTopRow}>
              <View style={styles.heroBadge}>
                <Text style={styles.heroBadgeText}>{appTitleLabel}</Text>
              </View>
              <Pressable
                onPress={() => router.push("/settings")}
                hitSlop={10}
                style={styles.settingsCog}
              >
                <Svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                  <Path
                    d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"
                    fill="#d3deea"
                  />
                  <Path
                    d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1.08-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l-.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1.08 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1.08 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9c.26.604.852.997 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1.08Z"
                    stroke="#d3deea"
                    strokeWidth="1.5"
                  />
                </Svg>
              </Pressable>
            </View>
          </View>

          <View style={styles.panel}>
            <Text style={[styles.meterValueCentered, isHolding && { color: "#d04f2d" }]}>
              {formatDuration(listeningMs)}
            </Text>

            <Pressable
              disabled={isSending}
              onPressIn={handlePressIn}
              onPressOut={handlePressOut}
              style={[
                styles.micButton,
                isHolding ? styles.holdingButton : styles.idleButton,
                isSending && styles.buttonDisabled,
              ]}
            >
              {isSending ? (
                <ActivityIndicator color="#fff6f3" size="large" />
              ) : (
                <Svg width="64" height="64" viewBox="0 0 24 24" fill="none">
                  <Path
                    d="M12 3a3 3 0 0 0-3 3v6a3 3 0 0 0 6 0V6a3 3 0 0 0-3-3z"
                    fill="#fff6f3"
                    stroke="#fff6f3"
                    strokeWidth="1"
                  />
                  <Path
                    d="M19 10v1a7 7 0 0 1-14 0v-1"
                    stroke="#fff6f3"
                    strokeWidth="2"
                    strokeLinecap="round"
                  />
                  <Path
                    d="M12 18v3"
                    stroke="#fff6f3"
                    strokeWidth="2"
                    strokeLinecap="round"
                  />
                </Svg>
              )}
            </Pressable>

            <Text style={styles.statusText}>
              {statusMessage || strings.readyToRecord}
            </Text>
            <Text style={styles.helperText}>
              {isHolding
                ? releaseLabel
                : backendUrl.trim()
                  ? holdLabel
                  : openSettingsHint}
            </Text>

            {displayText && (
              <View style={styles.transcriptBox}>
                <Text style={styles.transcriptLabel}>{strings.serverResponse}</Text>
                <Text style={styles.transcriptText}>{displayText}</Text>
              </View>
            )}
          </View>
        </ScrollView>
      </KeyboardAvoidingView>
    </View>
  );
}

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: "#f4efe4",
  },
  keyboardAvoidingView: {
    flex: 1,
  },
  scrollView: {
    flex: 1,
  },
  content: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    paddingVertical: 32,
    paddingHorizontal: 20,
    gap: 18,
  },
  hero: {
    backgroundColor: "transparent",
    paddingHorizontal: 22,
    paddingTop: 40,
  },
  heroTopRow: {
    alignItems: "center",
    flexDirection: "row",
    justifyContent: "space-between",
  },
  heroBadge: {
    backgroundColor: "#f2b15d",
    borderRadius: 999,
    paddingHorizontal: 12,
    paddingVertical: 6,
  },
  heroBadgeText: {
    color: "#13304a",
    fontSize: 12,
    fontWeight: "700",
    letterSpacing: 0.5,
    textTransform: "uppercase",
  },
  settingsCog: {
    alignItems: "center",
    justifyContent: "center",
    width: 40,
    height: 40,
    borderRadius: 999,
    backgroundColor: "#13304a",
    marginLeft: 12,
  },
  panel: {
    backgroundColor: "#fffaf1",
    borderColor: "#dccfb9",
    borderRadius: 24,
    borderWidth: 1,
    gap: 12,
    padding: 18,
    alignSelf: "center",
    maxWidth: 340,
  },
  meterValueCentered: {
    color: "#d04f2d",
    fontSize: 40,
    fontWeight: "800",
    textAlign: "center",
  },
  micButton: {
    alignItems: "center",
    borderRadius: 999,
    height: 164,
    justifyContent: "center",
    marginVertical: 6,
    width: 164,
    alignSelf: "center",
  },
  idleButton: {
    backgroundColor: "#13304a",
  },
  holdingButton: {
    backgroundColor: "#d04f2d",
    transform: [{ scale: 1.08 }],
  },
  buttonDisabled: {
    opacity: 0.45,
  },
  statusText: {
    color: "#1f2d3d",
    fontSize: 15,
    lineHeight: 21,
    textAlign: "center",
  },
  helperText: {
    color: "#665f54",
    fontSize: 13,
    lineHeight: 18,
    textAlign: "center",
  },
  transcriptBox: {
    backgroundColor: "#f7f0e0",
    borderRadius: 16,
    gap: 6,
    marginTop: 4,
    padding: 14,
    maxWidth: "100%",
  },
  transcriptLabel: {
    color: "#13304a",
    fontSize: 13,
    fontWeight: "700",
    textTransform: "uppercase",
    textAlign: "center",
  },
  transcriptText: {
    color: "#36475a",
    fontSize: 16,
    lineHeight: 22,
    textAlign: "center",
    fontWeight: "500",
  },
  responseBox: {
    backgroundColor: "#f7f0e0",
    borderRadius: 16,
    gap: 6,
    marginTop: 4,
    padding: 14,
  },
  responseLabel: {
    color: "#13304a",
    fontSize: 13,
    fontWeight: "700",
    textTransform: "uppercase",
    textAlign: "center",
  },
  responseText: {
    color: "#36475a",
    fontSize: 14,
    lineHeight: 20,
  },
});
