import { useEffect, useMemo, useState } from "react";
import { Navigate } from "react-router-dom";
import { startAuthentication } from "@simplewebauthn/browser";
import { supabase } from "@/lib/supabase-wrapper";
import { useAuth } from "@/contexts/AuthContext";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { useToast } from "@/hooks/use-toast";
import { Fingerprint, Loader2, AlertTriangle } from "lucide-react";

// Classify errors into actionable categories
type ErrorKind = 'credentials' | 'network' | 'backend' | 'session' | 'unknown';

function classifyError(err: unknown): ErrorKind {
  const msg = String((err as any)?.message || '').toLowerCase();
  if (msg.includes('invalid login') || msg.includes('invalid email') || msg.includes('credentials')) return 'credentials';
  if (msg.includes('failed to fetch') || msg.includes('network') || msg.includes('timed out') || msg.includes('timeout')) return 'network';
  if (msg.includes('edge function') || msg.includes('function') || msg.includes('500')) return 'backend';
  if (msg.includes('session')) return 'session';
  return 'unknown';
}

function userFriendlyMessage(kind: ErrorKind, raw: string): string {
  switch (kind) {
    case 'credentials': return 'Invalid email or password. Please check and try again.';
    case 'network': return 'Network issue — please check your connection and try again.';
    case 'backend': return 'Server is temporarily unavailable. Please wait a moment and retry.';
    case 'session': return 'Session could not be established. Please try again.';
    default: return raw || 'Something went wrong. Please try again.';
  }
}

type PasswordLoginResult = {
  data: { session?: { user?: unknown } | null } | null;
  error: Error | null;
};

type FunctionLoginResult = {
  data: { access_token?: string; refresh_token?: string; error?: string } | null;
  error: Error | null;
};

type SessionResult = {
  data: { session?: { user?: unknown } | null };
  error: Error | null;
};

function withTimeout<T>(promise: PromiseLike<T>, ms: number, message: string): Promise<T> {
  let timeoutId: ReturnType<typeof setTimeout> | undefined;

  const timeout = new Promise<never>((_, reject) => {
    timeoutId = setTimeout(() => reject(new Error(message)), ms);
  });

  return Promise.race([promise, timeout]).finally(() => {
    if (timeoutId) clearTimeout(timeoutId);
  });
}

async function loginViaPasswordFunction(identifier: string, password: string): Promise<FunctionLoginResult> {
  const response = await fetch(`${import.meta.env.VITE_SUPABASE_URL}/functions/v1/password-login`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      apikey: import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY,
    },
    body: JSON.stringify({ identifier, password }),
  });

  const data = await response.json().catch(() => null);
  if (!response.ok) {
    return { data, error: new Error(data?.error || "Invalid login credentials") };
  }

  return { data, error: null };
}

export default function Auth() {
  const { user, isReady, refreshAuth } = useAuth();
  const { toast } = useToast();

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [rememberMe, setRememberMe] = useState(true);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [isFingerprintLoading, setIsFingerprintLoading] = useState(false);
  const [slowWarning, setSlowWarning] = useState(false);

  const isBusy = useMemo(() => isSubmitting || isFingerprintLoading, [isSubmitting, isFingerprintLoading]);
  

  // Load remembered email
  useEffect(() => {
    localStorage.removeItem("rememberedPassword");
    const savedEmail = localStorage.getItem("rememberedEmail");
    const shouldRemember = localStorage.getItem("rememberMe") === "true";
    if (shouldRemember && savedEmail) {
      setEmail(savedEmail);
      setRememberMe(true);
    }
  }, []);

  const persistRememberMe = () => {
    if (rememberMe) {
      localStorage.setItem("rememberedEmail", email);
      localStorage.setItem("rememberMe", "true");
    } else {
      localStorage.removeItem("rememberedEmail");
      localStorage.removeItem("rememberMe");
    }
  };

  const clearPermissionCache = () => {
    sessionStorage.removeItem("permissions_cache");
    sessionStorage.removeItem("is_admin_cache");
    sessionStorage.removeItem("permissions_cache_timestamp");
  };

  // ===== PASSWORD LOGIN =====
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const identifier = email.trim();
    if (!identifier || !password) {
      toast({ title: "Missing fields", description: "Please enter your username or email and password.", variant: "destructive" });
      return;
    }
    const isEmail = identifier.includes("@");

    setIsSubmitting(true);
    setSlowWarning(false);

    // Show slow network warning after 8s
    const slowTimer = setTimeout(() => setSlowWarning(true), 8000);

    try {
      let verifiedSession: { user?: unknown } | null = null;

      if (!isEmail) {
        // Username login — always go through edge function to resolve username -> email
        const { data: fnData, error: fnError } = await withTimeout<FunctionLoginResult>(
          loginViaPasswordFunction(identifier, password),
          12000,
          'Login timed out. Please check your connection and try again.'
        );
        if (fnError) throw fnError;

        const accessToken = fnData?.access_token;
        const refreshToken = fnData?.refresh_token;
        if (!accessToken || !refreshToken) {
          throw new Error(fnData?.error || "Invalid login credentials");
        }

        const { data: sessionData, error: setErr } = await withTimeout<SessionResult>(
          supabase.auth.setSession({ access_token: accessToken, refresh_token: refreshToken }),
          10000,
          'Session setup timed out. Please try again.'
        );
        if (setErr) throw setErr;
        if (!sessionData.session?.user) {
          throw new Error("Session could not be created from server login");
        }
        verifiedSession = sessionData.session;
      } else {
        // Email login — primary: direct Supabase auth
        try {
          const { data, error } = await withTimeout<PasswordLoginResult>(
            supabase.auth.signInWithPassword({ email: identifier, password }),
            8000,
            'Login timed out. Please check your connection and try again.'
          );
          if (error) throw error;
          if (data?.session?.user) verifiedSession = data.session;
        } catch (directError: any) {
          const kind = classifyError(directError);
          if (kind === 'network') {
            try {
              const { data: fnData, error: fnError } = await withTimeout<FunctionLoginResult>(
                loginViaPasswordFunction(identifier, password),
                12000,
                'Backup login timed out. Please check your connection and try again.'
              );
              if (fnError) throw fnError;
              const accessToken = fnData?.access_token;
              const refreshToken = fnData?.refresh_token;
              if (!accessToken || !refreshToken) {
                throw new Error(fnData?.error || "Invalid login response from server");
              }
              const { data: sessionData, error: setErr } = await withTimeout<SessionResult>(
                supabase.auth.setSession({ access_token: accessToken, refresh_token: refreshToken }),
                10000,
                'Session setup timed out. Please try again.'
              );
              if (setErr) throw setErr;
              if (!sessionData.session?.user) {
                throw new Error("Session could not be created from server login");
              }
              verifiedSession = sessionData.session;
            } catch (fnFallbackError) {
              const fnKind = classifyError(fnFallbackError);
              if (fnKind === 'credentials') throw fnFallbackError;
              throw directError;
            }
          } else {
            throw directError;
          }
        }
      }


      if (!verifiedSession?.user) {
        throw new Error("Login completed but no session was created.");
      }

      const authReady = await refreshAuth(verifiedSession);
      if (!authReady) {
        throw new Error("Session could not be established. Please try again.");
      }

      clearPermissionCache();
      persistRememberMe();

      toast({ title: "Success", description: "Signed in successfully!", duration: 800 });
    } catch (error: any) {
      const kind = classifyError(error);
      toast({
        title: "Login failed",
        description: userFriendlyMessage(kind, error?.message),
        variant: "destructive",
      });
    } finally {
      clearTimeout(slowTimer);
      setSlowWarning(false);
      setIsSubmitting(false);
    }
  };

  // ===== FINGERPRINT LOGIN =====
  const handleFingerprintLogin = async () => {
    setIsFingerprintLoading(true);
    setSlowWarning(false);

    const slowTimer = setTimeout(() => setSlowWarning(true), 8000);

    try {
      // Step 1: Get challenge
      const { data: startData, error: startError } = await supabase.functions.invoke("webauthn-login-start", { body: {} });
      if (startError) throw startError;

      const optionsJSON = startData?.optionsJSON ?? startData?.options;
      if (!optionsJSON) throw new Error("Fingerprint challenge unavailable.");

      // Step 2: Authenticate with device
      const credential = await startAuthentication({ optionsJSON });

      // Step 3: Verify
      const { data: verifyData, error: verifyError } = await supabase.functions.invoke("webauthn-login-verify", {
        body: { credential, expectedChallenge: optionsJSON.challenge },
      });
      if (verifyError) throw verifyError;

      const accessToken = verifyData?.session?.access_token;
      const refreshToken = verifyData?.session?.refresh_token;

      if (!accessToken || !refreshToken) {
        throw new Error(verifyData?.error || "Fingerprint session unavailable.");
      }

      // Step 4: Set session
      const { data: sessionData, error: setErr } = await supabase.auth.setSession({
        access_token: accessToken,
        refresh_token: refreshToken,
      });
      if (setErr) throw setErr;
      if (!sessionData.session?.user) {
        throw new Error("Fingerprint session could not be created.");
      }

      const authReady = await refreshAuth(sessionData.session);
      if (!authReady) {
        throw new Error("Session could not be established. Please try again.");
      }

      clearPermissionCache();

      toast({ title: "Success", description: "Signed in with fingerprint.", duration: 800 });
    } catch (error: any) {
      const kind = classifyError(error);
      toast({
        title: "Fingerprint login failed",
        description: userFriendlyMessage(kind, error?.message),
        variant: "destructive",
      });
    } finally {
      clearTimeout(slowTimer);
      setSlowWarning(false);
      setIsFingerprintLoading(false);
    }
  };

  // Declarative redirect after successful login
  // Declarative redirects — after all hooks
  if (isReady && user) {
    return <Navigate to="/dashboard" replace />;
  }

  return (
    <div className="min-h-screen flex items-center justify-center bg-background p-4">
      <Card className="w-full max-w-md bg-card/90 backdrop-blur-sm border-border shadow-lg">
        <CardHeader className="space-y-3 text-center">
          <CardTitle className="text-2xl font-bold text-foreground">Login</CardTitle>
          <CardDescription>Sign in to continue to your dashboard</CardDescription>
        </CardHeader>
        <CardContent>
          <form onSubmit={handleSubmit} className="space-y-4">
            <div className="space-y-2">
              <Label htmlFor="email">Username or Email</Label>
              <Input
                id="email"
                type="text"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                placeholder="username or name@example.com"
                autoComplete="username"
                autoCapitalize="none"
                autoCorrect="off"
                spellCheck={false}
                required
              />
            </div>


            <div className="space-y-2">
              <Label htmlFor="password">Password</Label>
              <Input
                id="password"
                type="password"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                placeholder="••••••••"
                autoComplete="current-password"
                required
              />
            </div>

            <div className="flex items-center gap-2">
              <Checkbox
                id="remember"
                checked={rememberMe}
                onCheckedChange={(checked) => setRememberMe(Boolean(checked))}
              />
              <Label htmlFor="remember" className="text-sm text-muted-foreground">Remember email</Label>
            </div>

            {slowWarning && (
              <div className="flex items-center gap-2 text-sm text-accent-foreground bg-accent p-2 rounded">
                <AlertTriangle className="h-4 w-4 flex-shrink-0" />
                <span>Sign-in is taking longer than usual. Still trying — please wait...</span>
              </div>
            )}

            <Button type="submit" className="w-full" disabled={isBusy}>
              {isSubmitting ? (
                <span className="inline-flex items-center gap-2"><Loader2 className="h-4 w-4 animate-spin" />Signing in...</span>
              ) : (
                "Sign In"
              )}
            </Button>

            <Button type="button" variant="outline" className="w-full" onClick={handleFingerprintLogin} disabled={isBusy}>
              {isFingerprintLoading ? (
                <span className="inline-flex items-center gap-2"><Loader2 className="h-4 w-4 animate-spin" />Checking fingerprint...</span>
              ) : (
                <span className="inline-flex items-center gap-2"><Fingerprint className="h-4 w-4" />Login with Fingerprint</span>
              )}
            </Button>
          </form>
        </CardContent>
      </Card>
    </div>
  );
}
