import { Audio, InterruptionModeAndroid, InterruptionModeIOS } from "expo-av";
import { router, useFocusEffect } from "expo-router";
import { useCallback, useEffect, useRef, useState } from "react";
import Svg, { Path } from "react-native-svg";
import {
  ActivityIndicator,
  Alert,
  KeyboardAvoidingView,
  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")}`;
}

function buildMimeType(uri: string) {
  const extension = uri.split(".").pop()?.split("?")[0]?.toLowerCase();

  switch (extension) {
    case "wav":
      return "audio/wav";
    case "caf":
      return "audio/x-caf";
    case "webm":
      return "audio/webm";
    case "mp3":
      return "audio/mpeg";
    default:
      return "audio/m4a";
  }
}

function buildFileExtension(uri: string) {
  return uri.split(".").pop()?.split("?")[0]?.toLowerCase() || "m4a";
}

export default function RecorderScreen() {
  const [backendUrl, setBackendUrl] = useState("");
  const [authToken, setAuthToken] = useState("");
  const [fieldName, setFieldName] = useState("file");
  const [locale, setLocale] = useState<Locale>("ca");
  const [strings, setStrings] = useState(() => getStrings("ca"));
  const [recording, setRecording] = useState<Audio.Recording | null>(null);
  const [recordingUri, setRecordingUri] = useState<string | null>(null);
  const [recordingMs, setRecordingMs] = useState(0);
  const [statusMessage, setStatusMessage] = useState("");
  const [responsePreview, setResponsePreview] = useState("");
  const [isUploading, setIsUploading] = useState(false);
  const [isHolding, setIsHolding] = useState(false);
  const recordingRef = useRef<Audio.Recording | null>(null);

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

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

        if (!isMounted) {
          return;
        }

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

    void loadStoredValues();

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

  useFocusEffect(refreshSettings);

  useEffect(() => {
    if (!recording) {
      return;
    }

    const interval = setInterval(() => {
      void recording.getStatusAsync().then((status) => {
        if (typeof status.durationMillis === "number") {
          setRecordingMs(status.durationMillis ?? 0);
        }
      });
    }, 250);

    return () => {
      clearInterval(interval);
    };
  }, [recording]);

  useEffect(() => {
    return () => {
      if (recording) {
        void recording.stopAndUnloadAsync().catch(() => undefined);
      }
    };
  }, [recording]);

  async function startRecording() {
    try {
      setResponsePreview("");
      setRecordingUri(null);

      const permission = await Audio.requestPermissionsAsync();

      if (!permission.granted) {
        setStatusMessage(strings.micPermissionDenied);
        Alert.alert(
          strings.micAccessRequiredTitle,
          strings.micAccessRequiredMsg,
        );
        return;
      }

      await Audio.setAudioModeAsync({
        allowsRecordingIOS: true,
        interruptionModeAndroid: InterruptionModeAndroid.DoNotMix,
        interruptionModeIOS: InterruptionModeIOS.DoNotMix,
        playsInSilentModeIOS: true,
        shouldDuckAndroid: true,
        staysActiveInBackground: false,
      });

      const result = await Audio.Recording.createAsync(
        Audio.RecordingOptionsPresets.HIGH_QUALITY,
      );

      recordingRef.current = result.recording;
      setRecording(result.recording);
      setRecordingMs(0);
      setStatusMessage(strings.recording);
    } catch (error) {
      setStatusMessage(strings.couldNotStartRecording);
      Alert.alert(
        strings.recordingFailedTitle,
        error instanceof Error ? error.message : "",
      );
    }
  }

  async function stopRecordingAndUpload() {
    if (!recordingRef.current) {
      return;
    }

    try {
      const activeRecording = recordingRef.current;
      const currentStatus = await activeRecording.getStatusAsync();
      const durationMillis = currentStatus.durationMillis ?? 0;

      await activeRecording.stopAndUnloadAsync();
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: false,
        playsInSilentModeIOS: true,
      });

      const uri = activeRecording.getURI();
      recordingRef.current = null;
      setRecording(null);
      setRecordingMs(durationMillis);

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

      setRecordingUri(uri);
      setStatusMessage(strings.finishedUpload);

      const trimmedUrl = backendUrl.trim().replace(/\/+$/, '');
      const uploadUrl = trimmedUrl.endsWith('/audio/upload')
        ? trimmedUrl
        : `${trimmedUrl}/audio/upload`;
      if (uploadUrl) {
        try {
          const mimeType = buildMimeType(uri);
          const extension = buildFileExtension(uri);
          const formData = new FormData();

          formData.append(fieldName.trim() || "file", {
            name: `recording-${Date.now()}.${extension}`,
            type: mimeType,
            uri: uri,
          } as never);

          const headers: Record<string, string> = {};
          if (authToken.trim()) {
            headers.Authorization = `Bearer ${authToken.trim()}`;
          }

          const response = await fetch(uploadUrl, {
            method: "POST",
            headers,
            body: formData,
          });

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

          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 : "",
          );
        }
      } else {
        setStatusMessage(strings.noBackendUrl);
      }
    } catch (error) {
      recordingRef.current = null;
      setRecording(null);
      setStatusMessage(strings.stopFailedTitle);
      Alert.alert(
        strings.stopFailedTitle,
        error instanceof Error ? error.message : "",
      );
    }
  }

  async function handlePressIn() {
    if (isUploading) return;
    setIsHolding(true);
    await startRecording();
  }

  async function handlePressOut() {
    if (!isHolding) return;
    setIsHolding(false);
    await stopRecordingAndUpload();
  }

  async function uploadRecording(uriOverride?: string) {
    const targetUri = uriOverride ?? recordingUri;

    if (!targetUri) {
      return;
    }

    const trimmedUrl = backendUrl.trim().replace(/\/+$/, '');
    const uploadUrl = trimmedUrl.endsWith('/audio/upload')
      ? trimmedUrl
      : `${trimmedUrl}/audio/upload`;

    if (!uploadUrl) {
      Alert.alert(strings.missingBackendUrlTitle, strings.missingBackendUrlMsg);
      return;
    }

    try {
      setIsUploading(true);
      setStatusMessage(strings.uploadingRecording);
      setResponsePreview("");

      const mimeType = buildMimeType(targetUri);
      const extension = buildFileExtension(targetUri);
      const formData = new FormData();

      formData.append(fieldName.trim() || "file", {
        name: `recording-${Date.now()}.${extension}`,
        type: mimeType,
        uri: targetUri,
      } as never);

      const headers: Record<string, string> = {};

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

      const response = await fetch(uploadUrl, {
        method: "POST",
        headers,
        body: formData,
      });

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

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

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

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

  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(recordingMs)}
            </Text>

            <Pressable
              disabled={isUploading}
              onPressIn={handlePressIn}
              onPressOut={handlePressOut}
              style={[
                styles.micButton,
                isHolding ? styles.holdingButton : styles.idleButton,
                isUploading && styles.buttonDisabled,
              ]}
            >
              {isUploading ? (
                <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
                  : openSettingsLabel}
            </Text>

            {responsePreview ? (
              <View style={styles.responseBox}>
                <Text style={styles.responseLabel}>{serverResponseLabel}</Text>
                <Text style={styles.responseText}>{responsePreview}</Text>
              </View>
            ) : null}
          </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 }],
  },
  micButtonText: {
    color: "#fff6f3",
    fontSize: 20,
    fontWeight: "800",
  },
  recordingLabel: {
    fontSize: 18,
  },
  buttonDisabled: {
    opacity: 0.45,
  },
  statusText: {
    color: "#1f2d3d",
    fontSize: 15,
    lineHeight: 21,
    textAlign: "center",
  },
  helperText: {
    color: "#665f54",
    fontSize: 13,
    lineHeight: 18,
    textAlign: "center",
  },
  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,
  },
});
