import { Link, useRouter } from "expo-router";
import { useCallback, useEffect, useState } from "react";
import {
  Alert,
  Image,
  KeyboardAvoidingView,
  Platform,
  ScrollView,
  Text,
  TouchableOpacity,
  View,
} from "react-native";
import ReactNativeModal from "react-native-modal";

import { CustomButton } from "@/components/custom-button";
import { InputField } from "@/components/input-field";
import { OAuth } from "@/components/oauth";
import { OtpField } from "@/components/otp-field";
import { icons, images } from "@/constants";
import { ApiError, fetchAPI } from "@/lib/fetch";
import { getRememberedEmail, rememberEmail, useSession } from "@/lib/session";

const SignIn = () => {
  const router = useRouter();
  const { setSession } = useSession();
  const [form, setForm] = useState({
    email: "",
    password: "",
  });
  const [busy, setBusy] = useState(false);

  // On by default: a rider signing in on their own phone shouldn't have to
  // opt into staying signed in. Unchecking it shortens the session to 12h and
  // stops the address being prefilled next time.
  const [remember, setRemember] = useState(true);

  useEffect(() => {
    let cancelled = false;

    getRememberedEmail()
      .then((email) => {
        if (!email || cancelled) return;

        // SecureStore can resolve after the user has started typing, so only
        // fill a field that's still untouched.
        setForm((prevForm) =>
          prevForm.email ? prevForm : { ...prevForm, email },
        );
      })
      .catch(() => {
        // Nothing stored, or the keychain is unavailable: start blank.
      });

    return () => {
      cancelled = true;
    };
  }, []);

  // Forgot-password flow: "request" collects the email, "reset" collects the
  // emailed code and a new password.
  const [reset, setReset] = useState({
    state: "closed" as "closed" | "request" | "reset",
    email: "",
    code: "",
    password: "",
    devCode: "",
    error: "",
    busy: false,
  });

  const openReset = () =>
    setReset({
      state: "request",
      email: form.email,
      code: "",
      password: "",
      devCode: "",
      error: "",
      busy: false,
    });

  const closeReset = () =>
    setReset((prev) => ({ ...prev, state: "closed" }));

  const onRequestReset = async () => {
    if (!reset.email.trim()) {
      setReset((prev) => ({ ...prev, error: "Enter your email address." }));
      return;
    }

    setReset((prev) => ({ ...prev, busy: true, error: "" }));

    try {
      const response = await fetchAPI("/(api)/auth/forgot-password", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: reset.email.trim() }),
      });

      setReset((prev) => ({
        ...prev,
        state: "reset",
        busy: false,
        devCode:
          (response as { data?: { devCode?: string } })?.data?.devCode ?? "",
      }));
    } catch {
      // The endpoint hides whether the email exists, so move on regardless.
      setReset((prev) => ({ ...prev, state: "reset", busy: false }));
    }
  };

  const onSubmitReset = async () => {
    if (!/^\d{6}$/.test(reset.code)) {
      setReset((prev) => ({ ...prev, error: "Enter the 6-digit code." }));
      return;
    }

    if (reset.password.length < 8) {
      setReset((prev) => ({
        ...prev,
        error: "Password must be at least 8 characters.",
      }));
      return;
    }

    setReset((prev) => ({ ...prev, busy: true, error: "" }));

    try {
      const response = await fetchAPI("/(api)/auth/reset-password", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          email: reset.email.trim(),
          code: reset.code,
          password: reset.password,
        }),
      });

      await setSession(response.data);
      await rememberEmail(remember ? reset.email.trim() : null);
      setReset((prev) => ({ ...prev, state: "closed", busy: false }));
      router.replace("/");
    } catch (err: any) {
      setReset((prev) => ({
        ...prev,
        busy: false,
        error:
          err instanceof ApiError && err.status < 500
            ? err.message
            : "Could not reset your password. Please try again.",
      }));
    }
  };

  const onSignInPress = useCallback(async () => {
    if (busy) return;

    // Catch the blank-field case here: the server answers 400 for it, which
    // otherwise surfaces as a generic "could not sign in".
    if (!form.email.trim() || !form.password) {
      Alert.alert(
        "Missing information",
        "Enter both your email and your password.",
      );
      return;
    }

    setBusy(true);

    try {
      const response = await fetchAPI("/(api)/auth/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          email: form.email,
          password: form.password,
          remember,
        }),
      });

      await setSession(response.data);
      await rememberEmail(remember ? form.email.trim() : null);
      router.replace("/");
    } catch (err: any) {
      const message =
        err instanceof ApiError && err.status < 500
          ? err.message
          : "Could not sign in. Please try again.";

      Alert.alert("Error", message);

      // Only a rejected password is worth retyping. Clearing it after a
      // network blip or a 403 just makes the next attempt fail differently.
      if (err instanceof ApiError && err.status === 401) {
        setForm((prevForm) => ({ ...prevForm, password: "" }));
      }
    } finally {
      setBusy(false);
    }
  }, [busy, form.email, form.password, remember, setSession, router]);

  return (
    <KeyboardAvoidingView
      className="flex-1 bg-white"
      behavior={Platform.OS === "ios" ? "padding" : "height"}
      keyboardVerticalOffset={Platform.OS === "ios" ? 40 : 0}
    >
    <ScrollView
      className="flex-1 bg-white"
      keyboardShouldPersistTaps="handled"
      contentContainerStyle={{ flexGrow: 1 }}
      showsVerticalScrollIndicator={false}
    >
      <View className="flex-1 bg-white">
        <View className="relative w-full h-[250px]">
          <Image
            source={images.signUpCar}
            alt="Car"
            className="z-0 w-full h-[250px]"
            resizeMode="contain"
          />

          <Text className="text-2xl text-black font-JakartaSemiBold absolute bottom-5 left-5">
            Welcome 👋
          </Text>
        </View>

        <View className="p-5">
          <InputField
            label="Email"
            placeholder="karim@email.com"
            icon={icons.email}
            value={form.email}
            onChangeText={(value) =>
              setForm((prevForm) => ({
                ...prevForm,
                email: value,
              }))
            }
            keyboardType="email-address"
            autoComplete="email"
            textContentType="username"
          />

          <InputField
            label="Password"
            placeholder="••••••••"
            icon={icons.lock}
            secureTextEntry
            value={form.password}
            onChangeText={(value) =>
              setForm((prevForm) => ({
                ...prevForm,
                password: value,
              }))
            }
            autoComplete="current-password"
            textContentType="password"
          />

          <TouchableOpacity
            onPress={() => setRemember((current) => !current)}
            activeOpacity={0.7}
            accessibilityRole="checkbox"
            accessibilityState={{ checked: remember }}
            className="flex-row items-center mt-4"
          >
            <View
              className={`h-6 w-6 rounded-md items-center justify-center border-2 ${
                remember
                  ? "bg-primary-500 border-primary-500"
                  : "bg-white border-neutral-300"
              }`}
            >
              {remember ? (
                <Text className="text-white text-xs font-JakartaBold">✓</Text>
              ) : null}
            </View>

            <Text className="ml-3 font-JakartaMedium text-[15px] text-black">
              Keep me signed in
            </Text>
          </TouchableOpacity>

          <CustomButton
            title={busy ? "Signing in…" : "Sign In"}
            onPress={onSignInPress}
            disabled={busy}
            className="mt-6"
          />

          <TouchableOpacity onPress={openReset} className="mt-4">
            <Text className="text-primary-500 text-center font-JakartaMedium">
              Forgot password?
            </Text>
          </TouchableOpacity>

          <OAuth title="Sign in with Google" />

          <Link
            href="/sign-up"
            className="text-base text-center text-general-200 mt-10"
          >
            <Text>Don&apos;t have an account? </Text>
            <Text className="text-primary-500">Sign up</Text>
          </Link>
        </View>

        <ReactNativeModal
          isVisible={reset.state === "request"}
          onBackdropPress={closeReset}
        >
          <View className="bg-white px-7 py-9 rounded-2xl min-h-[280px]">
            <Text className="text-2xl font-JakartaExtraBold mb-2">
              Reset password
            </Text>

            <Text className="font-Jakarta mb-5">
              Enter your email and we&apos;ll send you a 6-digit reset code.
            </Text>

            <InputField
              label="Email"
              placeholder="karim@email.com"
              icon={icons.email}
              value={reset.email}
              keyboardType="email-address"
              autoComplete="email"
              textContentType="username"
              onChangeText={(email) =>
                setReset((prev) => ({ ...prev, email }))
              }
            />

            {reset.error ? (
              <Text className="text-rose-500 text-sm mt-1">{reset.error}</Text>
            ) : null}

            <CustomButton
              title={reset.busy ? "Sending…" : "Send Code"}
              onPress={onRequestReset}
              disabled={reset.busy}
              className="mt-5"
            />
          </View>
        </ReactNativeModal>

        <ReactNativeModal
          isVisible={reset.state === "reset"}
          onBackdropPress={closeReset}
        >
          <View className="bg-white px-7 py-9 rounded-2xl min-h-[300px]">
            <Text className="text-2xl font-JakartaExtraBold mb-2">
              Enter new password
            </Text>

            <Text className="font-Jakarta mb-5">
              We&apos;ve sent a reset code to {reset.email}
            </Text>

            {reset.devCode ? (
              <View className="bg-amber-50 border border-amber-300 rounded-xl p-3 mb-5">
                <Text className="text-sm text-amber-700 font-Jakarta">
                  Email delivery is not configured on this server. Your reset
                  code is <Text className="font-JakartaBold">{reset.devCode}</Text>
                </Text>
              </View>
            ) : null}

            <OtpField
              value={reset.code}
              onChange={(code) =>
                setReset((prev) => ({ ...prev, code, error: "" }))
              }
            />

            <InputField
              label="New password"
              icon={icons.lock}
              placeholder="••••••••"
              secureTextEntry
              value={reset.password}
              onChangeText={(password) =>
                setReset((prev) => ({ ...prev, password }))
              }
              autoComplete="new-password"
              textContentType="newPassword"
            />

            {reset.error ? (
              <Text className="text-rose-500 text-sm mt-1">{reset.error}</Text>
            ) : null}

            <CustomButton
              title={reset.busy ? "Resetting…" : "Reset Password"}
              onPress={onSubmitReset}
              disabled={reset.busy}
              className="mt-5 bg-emerald-500"
            />
          </View>
        </ReactNativeModal>
      </View>
    </ScrollView>
    </KeyboardAvoidingView>
  );
};

export default SignIn;
