import { MaterialCommunityIcons } from "@expo/vector-icons";
import * as Location from "expo-location";
import { router, useLocalSearchParams } from "expo-router";
import { useCallback, useEffect, useRef, useState } from "react";
import { ActivityIndicator, Text, TouchableOpacity, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";

import { CustomButton } from "@/components/custom-button";
import { PinAdjuster } from "@/components/pin-adjuster";
import { useT } from "@/lib/i18n";
import { addressForCoords } from "@/lib/reverse-geocode";
import { useLocationStore } from "@/store";

// "Move the pin to where you actually are."
//
// An address from autocomplete lands on whatever the geocoder considers the
// centre of that place — which can be the wrong side of a building, the wrong
// end of a long street, or the middle of a junction the driver can't stop in.
// The rider knows the doorway; this screen lets them say so, for the pickup
// and the drop-off alike.
//
// Reverse geocoding is debounced rather than run on every frame of the pan:
// the label only has to be right once the map stops.
const GEOCODE_DEBOUNCE_MS = 450;

// Falls back to Beirut, matching the map's own default, so the screen always
// has somewhere to open even before a fix arrives.
const FALLBACK = { latitude: 33.8938, longitude: 35.5018 };

type Coords = { latitude: number; longitude: number };

const AdjustPin = () => {
  const t = useT();
  const params = useLocalSearchParams<{ mode?: string }>();
  const mode = params.mode === "destination" ? "destination" : "origin";

  const {
    userLatitude,
    userLongitude,
    destinationLatitude,
    destinationLongitude,
    setUserLocation,
    setDestinationLocation,
  } = useLocationStore();

  // Open on the point being edited. A destination that hasn't been chosen yet
  // starts at the rider instead of an arbitrary city centre, because the place
  // they're going is usually near the place they are.
  const initial: Coords =
    mode === "origin"
      ? {
          latitude: userLatitude ?? FALLBACK.latitude,
          longitude: userLongitude ?? FALLBACK.longitude,
        }
      : {
          latitude: destinationLatitude ?? userLatitude ?? FALLBACK.latitude,
          longitude:
            destinationLongitude ?? userLongitude ?? FALLBACK.longitude,
        };

  const [coords, setCoords] = useState<Coords>(initial);
  const [address, setAddress] = useState<string | null>(null);
  const [resolving, setResolving] = useState(true);
  const debounce = useRef<ReturnType<typeof setTimeout>>();

  const resolve = useCallback((next: Coords) => {
    setCoords(next);
    clearTimeout(debounce.current);

    debounce.current = setTimeout(async () => {
      const label = await addressForCoords(next.latitude, next.longitude);
      setAddress(label);
      setResolving(false);
    }, GEOCODE_DEBOUNCE_MS);
  }, []);

  // Label the point the screen opened on, so the card isn't blank on arrival.
  useEffect(() => {
    resolve(initial);
    return () => clearTimeout(debounce.current);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const confirm = () => {
    const payload = {
      latitude: coords.latitude,
      longitude: coords.longitude,
      address: address ?? t("common.yourLocation"),
    };

    if (mode === "origin") setUserLocation(payload);
    else setDestinationLocation(payload);

    router.back();
  };

  // Jump back to the rider's own position — the usual reason to open this
  // screen is that the suggested pickup drifted away from where they're
  // standing.
  const recenter = async () => {
    try {
      const { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== "granted") return;

      const position = await Location.getLastKnownPositionAsync({
        maxAge: 60_000,
      });
      if (!position) return;

      setResolving(true);
      resolve({
        latitude: position.coords.latitude,
        longitude: position.coords.longitude,
      });
    } catch (error) {
      console.log("[ADJUST_PIN_RECENTER]: ", error);
    }
  };

  return (
    <View className="flex-1 bg-white dark:bg-neutral-950">
      <PinAdjuster
        initial={initial}
        onMoveStart={() => setResolving(true)}
        onSettled={resolve}
      />

      <SafeAreaView className="flex-1" pointerEvents="box-none">
        <View className="px-5 pt-2" pointerEvents="box-none">
          <TouchableOpacity
            onPress={() => router.back()}
            accessibilityLabel={t("common.back")}
            className="w-10 h-10 rounded-full bg-white dark:bg-neutral-900 items-center justify-center shadow-sm shadow-neutral-300 dark:shadow-neutral-950/40"
          >
            <MaterialCommunityIcons name="arrow-left" size={20} color="#0286ff" />
          </TouchableOpacity>
        </View>

        <View className="flex-1" pointerEvents="none" />

        <View className="px-5 pb-5" pointerEvents="box-none">
          <TouchableOpacity
            onPress={recenter}
            accessibilityLabel={t("adjustPin.recenter")}
            className="self-end mb-3 w-11 h-11 rounded-full bg-white dark:bg-neutral-900 items-center justify-center shadow-sm shadow-neutral-300 dark:shadow-neutral-950/40"
          >
            <MaterialCommunityIcons
              name="crosshairs-gps"
              size={20}
              color="#0286ff"
            />
          </TouchableOpacity>

          <View className="rounded-2xl bg-white dark:bg-neutral-900 p-5 shadow-sm shadow-neutral-300 dark:shadow-neutral-950/40">
            <Text className="text-xs font-JakartaSemiBold uppercase tracking-wide text-general-200 dark:text-neutral-500 mb-1">
              {mode === "origin"
                ? t("adjustPin.pickupLabel")
                : t("adjustPin.destinationLabel")}
            </Text>

            <View className="flex-row items-center min-h-[26px] mb-1">
              {resolving ? (
                <>
                  <ActivityIndicator size="small" color="#0286ff" />
                  <Text className="ml-2 font-JakartaMedium text-general-200 dark:text-neutral-400">
                    {t("adjustPin.locating")}
                  </Text>
                </>
              ) : (
                <Text
                  className="font-JakartaBold text-black dark:text-white text-base flex-1"
                  numberOfLines={2}
                >
                  {address}
                </Text>
              )}
            </View>

            <Text className="text-xs font-Jakarta text-general-200 dark:text-neutral-400 mb-4">
              {t("adjustPin.hint")}
            </Text>

            <CustomButton
              title={
                mode === "origin"
                  ? t("adjustPin.confirmPickup")
                  : t("adjustPin.confirmDestination")
              }
              onPress={confirm}
              disabled={resolving}
            />
          </View>
        </View>
      </SafeAreaView>
    </View>
  );
};

export default AdjustPin;
