import { MaterialCommunityIcons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
import { useCallback, useEffect, useRef, useState } from "react";
import { Alert, Text, TouchableOpacity, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { RTCView } from "react-native-webrtc";

import { fetchAPI } from "@/lib/fetch";
import { useT } from "@/lib/i18n";
import { useCall } from "@/lib/use-call";
import type { ChatActiveRide } from "@/types/type";

// In-app WebRTC audio call screen. Two entry modes:
//   mode=start   — caller opened this from the chat header; we place the call.
//   mode=incoming — CallWatcher detected a ringing call; we attach and wait
//                  for the user to Accept/Decline.
// Either way the authoritative ride/role/peer come from GET /(api)/chat/active
// (so a stale nav param never dials the wrong ride).

const Call = () => {
  const t = useT();
  const params = useLocalSearchParams<{
    rideId?: string;
    role?: "rider" | "driver";
    mode?: "start" | "incoming";
  }>();

  const [active, setActive] = useState<ChatActiveRide | null>(null);
  const [resolving, setResolving] = useState(true);

  const call = useCall();
  const startedRef = useRef(false);

  // Resolve the active ride + peer once, then kick off the right flow.
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const res = await fetchAPI("/(api)/chat/active");
        const a = (res.data ?? null) as ChatActiveRide | null;
        if (cancelled) return;
        setActive(a);
        if (!a) return;

        if (startedRef.current) return;
        startedRef.current = true;
        const peerName = a.peer?.name ?? "";
        if (params.mode === "start") {
          void call.startCall(a.ride_id, a.role, peerName);
        } else {
          call.watch(a.ride_id, a.role, peerName);
        }
      } catch (err) {
        console.log("[CALL_SCREEN_RESOLVE]: ", err);
      } finally {
        if (!cancelled) setResolving(false);
      }
    })();
    return () => {
      cancelled = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Surface a mic-permission denial and back out.
  useEffect(() => {
    if (call.micError) {
      Alert.alert(t("call.micDeniedTitle"), t("call.micDeniedBody"), [
        { text: "OK", onPress: () => router.back() },
      ]);
    }
  }, [call.micError, t]);

  // When the call reaches a terminal state, show the label briefly, then
  // leave the screen so the user returns to where they came from.
  useEffect(() => {
    if (call.status !== "ended") return;
    const timer = setTimeout(() => router.back(), 1200);
    return () => clearTimeout(timer);
  }, [call.status]);

  const peerName = active?.peer?.name ?? call.peerName ?? "";

  const handleEnd = useCallback(() => {
    void call.endCall();
  }, [call]);
  const handleAccept = useCallback(() => {
    void call.answerCall();
  }, [call]);
  const handleDecline = useCallback(() => {
    void call.declineCall();
  }, [call]);

  if (resolving) {
    return (
      <SafeAreaView className="flex-1 bg-white dark:bg-neutral-950 items-center justify-center">
        <Text className="text-general-200 dark:text-neutral-400">
          {t("call.connecting")}
        </Text>
      </SafeAreaView>
    );
  }

  if (!active) {
    return (
      <SafeAreaView className="flex-1 bg-white dark:bg-neutral-950 items-center justify-center px-7">
        <Text className="text-base text-center text-general-200 dark:text-neutral-400">
          {t("call.unavailable")}
        </Text>
        <TouchableOpacity
          onPress={() => router.back()}
          className="mt-6 px-6 py-3 rounded-full bg-general-400"
        >
          <Text className="text-white font-JakartaBold">
            {t("call.cancel")}
          </Text>
        </TouchableOpacity>
      </SafeAreaView>
    );
  }

  return (
    <SafeAreaView className="flex-1 bg-white dark:bg-neutral-950 items-center justify-between py-10">
      {/* Audio sink — hidden; keeps the native audio pipeline attached even
          though this is an audio-only call (RTCView is the stream sink). */}
      {call.remoteStream ? (
        <RTCView
          streamURL={call.remoteStream.toURL()}
          className="w-1 h-1 opacity-0"
        />
      ) : null}

      {/* Peer identity + status */}
      <View className="items-center mt-16">
        <View className="w-28 h-28 rounded-full bg-general-400 items-center justify-center mb-6">
          <Text className="text-4xl font-JakartaBold text-white">
            {(peerName.trim()[0] ?? "?").toUpperCase()}
          </Text>
        </View>
        <Text className="text-2xl font-JakartaBold text-black dark:text-white">
          {peerName}
        </Text>
        <Text className="text-base mt-1 text-general-200 dark:text-neutral-400">
          {call.status === "incoming"
            ? t("call.incoming")
            : call.status === "outgoing" || call.status === "connecting"
              ? t("call.connectingWith", { name: peerName })
              : call.status === "in-call"
                ? t("call.inCall")
                : call.status === "ended"
                  ? t("call.ended")
                  : t("call.connecting")}
        </Text>
      </View>

      {/* Controls vary by state */}
      <View className="flex-row items-center justify-center mb-10">
        {call.status === "incoming" ? (
          <>
            <CallButton
              icon="phone-hangup"
              color="#ef4444"
              label={t("call.decline")}
              onPress={handleDecline}
            />
            <CallButton
              icon="phone"
              color="#22c55e"
              label={t("call.accept")}
              onPress={handleAccept}
            />
          </>
        ) : (
          <>
            <CallButton
              icon={call.muted ? "microphone-off" : "microphone"}
              color={call.muted ? "#ef4444" : "#6b7280"}
              label={call.muted ? t("call.unmute") : t("call.mute")}
              onPress={call.toggleMute}
            />
            <CallButton
              icon="phone-hangup"
              color="#ef4444"
              label={t("call.end")}
              onPress={handleEnd}
            />
            <CallButton
              icon={call.speakerOn ? "volume-high" : "volume-off"}
              color={call.speakerOn ? "#0286ff" : "#6b7280"}
              label={call.speakerOn ? t("call.speaker") : t("call.speakerOff")}
              onPress={call.toggleSpeaker}
            />
          </>
        )}
      </View>
    </SafeAreaView>
  );
};

const CallButton = ({
  icon,
  color,
  label,
  onPress,
}: {
  icon: React.ComponentProps<typeof MaterialCommunityIcons>["name"];
  color: string;
  label: string;
  onPress: () => void;
}) => (
  <TouchableOpacity
    onPress={onPress}
    className="items-center mx-6"
    hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
  >
    <View
      className="w-16 h-16 rounded-full items-center justify-center"
      style={{ backgroundColor: color }}
    >
      <MaterialCommunityIcons name={icon} size={28} color="white" />
    </View>
    <Text className="text-xs mt-2 text-general-200 dark:text-neutral-400">
      {label}
    </Text>
  </TouchableOpacity>
);

export default Call;
