import { Link, router } from "expo-router";
import * as Linking from "expo-linking";
import { useEffect, useState } from "react";
import { Pressable, StyleSheet, Text, View } from "react-native";

import { AuthCard } from "@/components/auth/AuthCard";
import { AuthCardHeader } from "@/components/auth/AuthCardHeader";
import { AuthDivider } from "@/components/auth/AuthDivider";
import { AuthNotice } from "@/components/auth/AuthNotice";
import { AuthScreenLayout } from "@/components/auth/AuthScreenLayout";
import { AuthServerPicker } from "@/components/AuthServerPicker";
import { LegalAgreementNotice } from "@/components/legal/LegalAgreementNotice";
import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
import { fonts, spacing } from "@/constants/theme";
import { useAccounts } from "@/contexts/AccountsContext";
import { useAuthClient } from "@/contexts/AuthContext";
import { useAppTheme } from "@/contexts/ThemeContext";
import { fetchAuthCapabilities } from "@/lib/auth-capabilities";
import { signInWithAuthentik } from "@/lib/auth-oauth";
import { completeSignInAfterAuth } from "@/lib/complete-sign-in";
import { formatAuthErrorMessage } from "@/lib/trpc-errors";
import { isRequiredString, isValidEmail, useFieldVisibility } from "@/lib/form-validation";

export default function SignInScreen() {
  const authClient = useAuthClient();
  const { apiUrl, activeAccountId, registerAccount } = useAccounts();
  const { colors } = useAppTheme();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
  const [serverReady, setServerReady] = useState(true);
  const [authentikEnabled, setAuthentikEnabled] = useState(false);
  const [signupsDisabled, setSignupsDisabled] = useState(false);
  const { touch, visible, markSubmitted } = useFieldVisibility();

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

    void fetchAuthCapabilities(apiUrl).then((capabilities) => {
      if (cancelled) return;
      setAuthentikEnabled(capabilities.authentik);
      setSignupsDisabled(capabilities.signupsDisabled);
    });

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

  const emailValidationError = !email.trim()
    ? "Email is required"
    : isValidEmail(email)
      ? undefined
      : "Enter a valid email";
  const passwordValidationError = password.trim() ? undefined : "Password is required";
  const canSignIn = isValidEmail(email) && isRequiredString(password) && serverReady;

  async function finishSignIn() {
    const completed = await completeSignInAfterAuth(authClient, {
      apiUrl,
      activeAccountId,
      registerAccount,
    });

    if (!completed) {
      setError("Signed in but session was not available. Try again.");
    }
  }

  async function handleSignIn() {
    markSubmitted();
    if (!canSignIn) return;
    setError(null);
    setLoading(true);

    try {
      const { error: signInError } = await authClient.signIn.email({
        email: email.trim(),
        password,
      });

      if (signInError) {
        setError(formatAuthErrorMessage(signInError));
        return;
      }

      await finishSignIn();
    } finally {
      setLoading(false);
    }
  }

  async function handleAuthentikSignIn() {
    if (!serverReady) return;
    setError(null);
    setLoading(true);

    try {
      const { error: oauthError } = await signInWithAuthentik(
        authClient,
        Linking.createURL("/"),
      );

      if (oauthError) {
        setError(formatAuthErrorMessage(oauthError));
        return;
      }

      await finishSignIn();
    } finally {
      setLoading(false);
    }
  }

  return (
    <AuthScreenLayout>
      <AuthCard>
        <AuthCardHeader title="Welcome back" description="Sign in to your workspace" />

        <AuthServerPicker onReadyChange={setServerReady} embedded />

        {signupsDisabled ? (
          <AuthNotice>New account registration is currently disabled.</AuthNotice>
        ) : null}

        {authentikEnabled ? (
          <View style={styles.ssoSection}>
            <Button
              title="Sign in with Authentik"
              variant="secondary"
              loading={loading}
              disabled={!serverReady}
              onPress={() => void handleAuthentikSignIn()}
            />
            <AuthDivider />
          </View>
        ) : null}

        <View style={styles.form}>
          <Input
            label="Email"
            leftIcon="mail-outline"
            autoCapitalize="none"
            autoComplete="email"
            keyboardType="email-address"
            value={email}
            onChangeText={setEmail}
            onBlur={() => touch("email")}
            placeholder="you@example.com"
            required
            error={visible("email") ? emailValidationError : undefined}
          />
          <Input
            label="Password"
            leftIcon="lock-closed-outline"
            secureTextEntry
            autoComplete="password"
            value={password}
            onChangeText={setPassword}
            onBlur={() => touch("password")}
            placeholder="••••••••"
            required
            error={visible("password") ? passwordValidationError : undefined}
            labelAccessory={
              <Pressable onPress={() => router.push("/(auth)/forgot-password")} hitSlop={8}>
                <Text style={[styles.forgot, { color: colors.mutedForeground }]}>
                  Forgot password?
                </Text>
              </Pressable>
            }
          />

          {error ? (
            <Text style={[styles.error, { color: colors.destructive }]}>{error}</Text>
          ) : null}

          <Button
            title={loading ? "Signing in…" : "Sign in"}
            loading={loading}
            disabled={!canSignIn}
            showArrow={!loading}
            onPress={handleSignIn}
          />
        </View>

        {!signupsDisabled ? (
          <Text style={[styles.footer, { color: colors.mutedForeground }]}>
            Don&apos;t have an account?{" "}
            <Link href="/(auth)/register" style={[styles.link, { color: colors.foreground }]}>
              Create account
            </Link>
          </Text>
        ) : null}

        <LegalAgreementNotice action="signing in" />
      </AuthCard>
    </AuthScreenLayout>
  );
}

const styles = StyleSheet.create({
  ssoSection: {
    gap: spacing.md,
  },
  form: {
    gap: spacing.md,
  },
  forgot: {
    fontFamily: fonts.bodyMedium,
    fontSize: 12,
  },
  error: {
    fontSize: 14,
    fontFamily: fonts.body,
  },
  footer: {
    textAlign: "center",
    fontSize: 14,
    fontFamily: fonts.body,
  },
  link: {
    fontFamily: fonts.bodySemiBold,
  },
});
