import { Audio, InterruptionModeAndroid, InterruptionModeIOS } from "expo-av";
import { router, useFocusEffect } from "expo-router";
import { useCallback, useEffect, useState } from "react";
import {
  ActivityIndicator,
  Alert,
  KeyboardAvoidingView,
  Platform,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { loadRecorderSettings } from "@/lib/recorder-settings";

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 [recording, setRecording] = useState<Audio.Recording | null>(null);
  const [recordingUri, setRecordingUri] = useState<string | null>(null);
  const [recordingMs, setRecordingMs] = useState(0);
  const [statusMessage, setStatusMessage] = useState(
    "Ready to record and send audio.",
  );
  const [responsePreview, setResponsePreview] = useState("");
  const [isUploading, setIsUploading] = useState(false);

  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);
      } catch {
        if (isMounted) {
          setStatusMessage("Could not load saved backend settings.");
        }
      }
    }

    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("Microphone permission was denied.");
        Alert.alert(
          "Microphone access required",
          "Enable microphone access to record audio.",
        );
        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,
      );

      setRecording(result.recording);
      setRecordingMs(0);
      setStatusMessage("Recording in progress.");
    } catch (error) {
      setStatusMessage("Recording could not be started.");
      Alert.alert(
        "Recording failed",
        error instanceof Error ? error.message : "Unknown recording error.",
      );
    }
  }

  async function stopRecording() {
    if (!recording) {
      return;
    }

    try {
      const activeRecording = recording;
      const currentStatus = await activeRecording.getStatusAsync();

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

      const uri = activeRecording.getURI();
      setRecording(null);
      setRecordingMs(currentStatus.durationMillis ?? recordingMs);
      setRecordingUri(uri);
      setStatusMessage(
        uri ? "Recording finished. Preparing to send voice message." : "Recording finished.",
      );

      if (uri && backendUrl.trim()) {
        await uploadRecording(uri);
      }
    } catch (error) {
      setStatusMessage("Recording could not be stopped cleanly.");
      Alert.alert(
        "Stop failed",
        error instanceof Error ? error.message : "Unknown stop error.",
      );
    }
  }

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

    if (!targetUri) {
      return;
    }

    const trimmedUrl = backendUrl.trim();

    if (!trimmedUrl) {
      Alert.alert("Missing backend URL", "Enter the backend endpoint first.");
      return;
    }

    try {
      setIsUploading(true);
      setStatusMessage("Uploading recording.");
      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(trimmedUrl, {
        method: "POST",
        headers,
        body: formData,
      });

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

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

      setStatusMessage("Upload complete.");
    } catch (error) {
      setStatusMessage("Upload failed.");
      Alert.alert(
        "Upload failed",
        error instanceof Error ? error.message : "Unknown upload error.",
      );
    } finally {
      setIsUploading(false);
    }
  }

  return (
    <SafeAreaView 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}>Assistant Voice</Text>
              </View>
              <Pressable onPress={() => router.push("/settings")} style={styles.settingsLink}>
                <Text style={styles.settingsLinkText}>Settings</Text>
              </Pressable>
            </View>
            <Text style={styles.subtitle}>
              Record a voice message and send it to your backend.
            </Text>
          </View>

          <View style={styles.panel}>
            <Text style={styles.meterValueCentered}>
              {formatDuration(recordingMs)}
            </Text>

            <Pressable
              disabled={isUploading}
              onPress={recording ? stopRecording : startRecording}
              style={[
                styles.micButton,
                recording ? styles.stopButton : styles.recordButton,
                isUploading && styles.buttonDisabled,
              ]}
            >
              {isUploading ? (
                <ActivityIndicator color="#fff6f3" size="large" />
              ) : (
                <Text style={styles.micButtonText}>
                  {recording ? "Stop" : "Record"}
                </Text>
              )}
            </Pressable>

            <Text style={styles.statusText}>{statusMessage}</Text>
            <Text style={styles.helperText}>
              {backendUrl.trim()
                ? recording
                  ? "Tap again when you finish speaking."
                  : "Tap the button to start a new voice message."
                : "Open settings to add your backend URL before sending voice messages."}
            </Text>

            {responsePreview ? (
              <View style={styles.responseBox}>
                <Text style={styles.responseLabel}>Server response</Text>
                <Text style={styles.responseText}>{responsePreview}</Text>
              </View>
            ) : null}
          </View>
        </ScrollView>
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: "#f4efe4",
  },
  keyboardAvoidingView: {
    flex: 1,
  },
  scrollView: {
    flex: 1,
  },
  content: {
    paddingHorizontal: 20,
    paddingBottom: 32,
    paddingTop: 8,
    gap: 18,
  },
  hero: {
    backgroundColor: "#13304a",
    borderRadius: 28,
    paddingHorizontal: 22,
    paddingVertical: 24,
    gap: 12,
  },
  heroTopRow: {
    alignItems: "center",
    flexDirection: "row",
    justifyContent: "space-between",
  },
  heroBadge: {
    alignSelf: "flex-start",
    backgroundColor: "#f2b15d",
    borderRadius: 999,
    paddingHorizontal: 12,
    paddingVertical: 6,
  },
  heroBadgeText: {
    color: "#13304a",
    fontSize: 12,
    fontWeight: "700",
    letterSpacing: 0.5,
    textTransform: "uppercase",
  },
  settingsLink: {
    borderColor: "#58718d",
    borderRadius: 999,
    borderWidth: 1,
    paddingHorizontal: 12,
    paddingVertical: 7,
  },
  settingsLinkText: {
    color: "#d3deea",
    fontSize: 13,
    fontWeight: "700",
  },
  subtitle: {
    color: "#d3deea",
    fontSize: 16,
    lineHeight: 22,
  },
  panel: {
    backgroundColor: "#fffaf1",
    borderColor: "#dccfb9",
    borderRadius: 24,
    borderWidth: 1,
    gap: 12,
    padding: 18,
  },
  meterValueCentered: {
    color: "#d04f2d",
    fontSize: 40,
    fontWeight: "800",
    textAlign: "center",
  },
  micButton: {
    alignItems: "center",
    borderRadius: 999,
    height: 164,
    justifyContent: "center",
    marginVertical: 6,
    width: 164,
    alignSelf: "center",
  },
  recordButton: {
    backgroundColor: "#d04f2d",
  },
  stopButton: {
    backgroundColor: "#8c1c13",
  },
  micButtonText: {
    color: "#fff6f3",
    fontSize: 24,
    fontWeight: "800",
  },
  buttonDisabled: {
    opacity: 0.45,
  },
  statusText: {
    color: "#1f2d3d",
    fontSize: 15,
    lineHeight: 21,
  },
  helperText: {
    color: "#665f54",
    fontSize: 13,
    lineHeight: 18,
  },
  responseBox: {
    backgroundColor: "#f7f0e0",
    borderRadius: 16,
    gap: 6,
    marginTop: 4,
    padding: 14,
  },
  responseLabel: {
    color: "#13304a",
    fontSize: 13,
    fontWeight: "700",
    textTransform: "uppercase",
  },
  responseText: {
    color: "#36475a",
    fontSize: 14,
    lineHeight: 20,
  },
});
