import { router, useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { ActivityIndicator, Alert, Text, TouchableOpacity, View } from "react-native";

import { CustomButton } from "@/components/custom-button";
import { RideLayout } from "@/components/ride-layout";
import { SERVICES } from "@/constants/services";
import { ApiError, fetchAPI } from "@/lib/fetch";
import { calculateTripFare } from "@/lib/map";
import { formatLBP } from "@/lib/pricing";
import { requestRide } from "@/lib/request-ride";
import { useSession } from "@/lib/session";
import { formatTime, haversine } from "@/lib/utils";
import { useLocationStore, useServiceStore } from "@/store";

type PaymentMethod = "cash" | "card";

type NearbyDriver = {
  id: number;
  first_name: string;
  latitude: number;
  longitude: number;
};

// Confirm-ride is now the request screen: the rider no longer browses and
// picks a driver. They see a single fare estimate + nearest-driver ETA, pick a
// payment method, and tap Request — auto-match assigns the driver and they're
// routed to the live status screen.
const ConfirmRide = () => {
  const params = useLocalSearchParams<{ service?: string }>();
  const {
    userAddress,
    userLatitude,
    userLongitude,
    destinationAddress,
    destinationLatitude,
    destinationLongitude,
  } = useLocationStore();
  const { service: storeService, setService } = useServiceStore();
  const { user } = useSession();

  const service = params.service ?? storeService;
  const selected = SERVICES.find((s) => s.id === service) ?? SERVICES[0];

  const [method, setMethod] = useState<PaymentMethod>("cash");
  const [estimate, setEstimate] = useState<{
    fare: string;
    durationSeconds: number;
  } | null>(null);
  const [nearestEta, setNearestEta] = useState<number | null>(null);
  const [driversOnline, setDriversOnline] = useState<number | null>(null);
  const [estimating, setEstimating] = useState(true);
  const [processing, setProcessing] = useState(false);

  // Trip fare estimate — one Directions call for the trip leg, recomputed when
  // the route or service changes. Independent of driver availability.
  useEffect(() => {
    if (
      !userLatitude ||
      !userLongitude ||
      !destinationLatitude ||
      !destinationLongitude
    )
      return;

    let cancelled = false;
    setEstimating(true);

    const run = async () => {
      const trip = await calculateTripFare({
        userLatitude,
        userLongitude,
        destinationLatitude,
        destinationLongitude,
        service: selected.id,
      });
      if (cancelled) return;
      setEstimate(
        trip
          ? { fare: trip.fare, durationSeconds: trip.durationSeconds }
          : null,
      );
    };

    void run().finally(() => {
      if (!cancelled) setEstimating(false);
    });

    return () => {
      cancelled = true;
    };
  }, [
    userLatitude,
    userLongitude,
    destinationLatitude,
    destinationLongitude,
    selected.id,
  ]);

  // Online-driver availability for the selected service, polled so the "no
  // drivers" state self-heals the moment a driver of this service comes
  // online. The nearest driver's pickup ETA is resolved alongside the count.
  useEffect(() => {
    if (!userLatitude || !userLongitude) return;

    let cancelled = false;

    const check = async () => {
      try {
        const res = await fetchAPI(
          `/(api)/driver/nearby?service=${selected.id}&lat=${userLatitude}&lng=${userLongitude}`,
        );
        const drivers = (res.data ?? []) as NearbyDriver[];
        if (cancelled) return;
        setDriversOnline(drivers.length);
        if (drivers.length === 0) {
          setNearestEta(null);
          return;
        }
        const nearest = drivers
          .map((d) => ({
            d,
            dist: haversine(
              userLatitude,
              userLongitude,
              d.latitude,
              d.longitude,
            ),
          }))
          .sort((a, b) => a.dist - b.dist)[0].d;

        const directionsRes = await fetch(
          `https://maps.googleapis.com/maps/api/directions/json?origin=${nearest.latitude},${nearest.longitude}&destination=${userLatitude},${userLongitude}&key=${process.env.EXPO_PUBLIC_GOOGLE_API_KEY}`,
        );
        const data = await directionsRes.json();
        const leg = data.routes?.[0]?.legs?.[0];
        if (!cancelled)
          setNearestEta(leg ? Math.round(leg.duration.value / 60) : null);
      } catch {
        if (!cancelled) {
          setDriversOnline(null);
          setNearestEta(null);
        }
      }
    };

    void check();
    const timer = setInterval(() => void check(), 10000);
    return () => {
      cancelled = true;
      clearInterval(timer);
    };
  }, [userLatitude, userLongitude, selected.id]);

  const request = async () => {
    if (!userLatitude || !userLongitude || !destinationLatitude || !destinationLongitude) {
      Alert.alert("Missing route", "Please set a pickup and destination first.");
      return;
    }
    if (!estimate) {
      Alert.alert("No estimate", "We couldn't estimate this fare. Please try again.");
      return;
    }

    // Nested so the guards above narrow userLatitude/estimate to non-null for
    // the card-confirm callback as well as the direct cash path.
    const doRequest = async () => {
      setProcessing(true);
      try {
        // Keep the store in sync with whatever service we resolved for this ride.
        setService(selected.id);

        const { ride } = await requestRide({
          method,
          service: selected.id,
          user: { name: user?.name ?? "", email: user?.email ?? "" },
          origin: {
            address: userAddress ?? "",
            latitude: userLatitude,
            longitude: userLongitude,
          },
          destination: {
            address: destinationAddress ?? "",
            latitude: destinationLatitude,
            longitude: destinationLongitude,
          },
          rideTimeSeconds: estimate.durationSeconds,
          fareCents: Math.round(parseFloat(estimate.fare) * 100),
        });

        router.replace(`/(root)/book-ride?id=${ride.ride_id}`);
      } catch (err) {
        console.log("[REQUEST_RIDE]: ", err);
        const msg =
          err instanceof ApiError
            ? err.message
            : "Something went wrong while booking your ride. Please try again.";
        Alert.alert("Error", msg);
      } finally {
        setProcessing(false);
      }
    };

    if (method === "card") {
      Alert.alert(
        "Pay by card",
        `Your card will be charged $${estimate.fare}.`,
        [
          { text: "Cancel", style: "cancel" },
          { text: "Continue", onPress: () => void doRequest() },
        ],
      );
    } else {
      void doRequest();
    }
  };

  return (
    <RideLayout title="Request Ride" snapPoints={["60%", "88%"]}>
      <Text className="text-xl font-JakartaSemiBold mb-1">Your trip</Text>

      <View className="flex-row items-center gap-x-2 mb-1">
        <Text className="text-general-200 text-xs">Pickup</Text>
      </View>
      <Text className="font-JakartaMedium mb-3" numberOfLines={1}>
        {userAddress}
      </Text>

      <View className="flex-row items-center gap-x-2 mb-1">
        <Text className="text-general-200 text-xs">Destination</Text>
      </View>
      <Text className="font-JakartaMedium mb-4" numberOfLines={1}>
        {destinationAddress}
      </Text>

      <View className="flex-row items-center justify-between bg-general-500 rounded-2xl p-4 mb-4">
        <View>
          <Text className="text-general-200 text-xs font-JakartaMedium">
            {selected.label} · {selected.tagline}
          </Text>
          <Text className="text-general-200 text-xs mt-1">
            Trip time {estimate ? formatTime(estimate.durationSeconds / 60) : "…"}
          </Text>
        </View>
        <View className="items-end">
          <Text className="text-2xl font-JakartaExtraBold">
            {estimating ? "…" : estimate ? `$${estimate.fare}` : "—"}
          </Text>
          {estimate ? (
            <Text className="text-xs text-general-200">
              ≈ {formatLBP(parseFloat(estimate.fare))}
            </Text>
          ) : null}
        </View>
      </View>

      <Text
        className={`text-base font-JakartaMedium mb-2 ${
          driversOnline === 0 ? "text-rose-500" : "text-general-200"
        }`}
      >
        {driversOnline === 0
          ? `No ${selected.label} drivers online right now`
          : nearestEta == null
            ? "Finding drivers nearby…"
            : `Nearest driver ≈ ${nearestEta} min away`}
      </Text>

      <Text className="text-lg font-JakartaSemiBold mt-2 mb-2">
        Payment Method
      </Text>
      <View className="flex-row gap-x-3 mb-2">
        <TouchableOpacity
          onPress={() => setMethod("cash")}
          className={`flex-1 items-center py-3 rounded-xl border ${
            method === "cash"
              ? "bg-general-600 border-primary-500"
              : "bg-white border-general-700"
          }`}
        >
          <Text
            className={`font-JakartaMedium ${
              method === "cash" ? "text-white" : "text-black"
            }`}
          >
            💵 Cash
          </Text>
        </TouchableOpacity>
        <TouchableOpacity
          onPress={() => setMethod("card")}
          className={`flex-1 items-center py-3 rounded-xl border ${
            method === "card"
              ? "bg-general-600 border-primary-500"
              : "bg-white border-general-700"
          }`}
        >
          <Text
            className={`font-JakartaMedium ${
              method === "card" ? "text-white" : "text-black"
            }`}
          >
            💳 Card
          </Text>
        </TouchableOpacity>
      </View>

      <CustomButton
        title={
          processing
            ? "Requesting…"
            : driversOnline === 0
              ? "No drivers online"
              : method === "cash"
                ? "Request Ride · Pay cash to driver"
                : "Request Ride · Pay by card"
        }
        className="mt-4"
        onPress={request}
        disabled={processing || estimating || !estimate || driversOnline === 0}
      />
    </RideLayout>
  );
};

export default ConfirmRide;