"use client";

import { Suspense, useEffect, useState, useCallback } from "react";
import type { ReactElement } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Loader2 } from "lucide-react";
import type { AuthConfigResponse, AuthProviderConfig } from "@mosaic/shared";
import { AuthShell, AuthCard, AuthBrand, AuthStatusPill } from "@mosaic/ui";
import { API_BASE_URL, IS_MOCK_AUTH_MODE } from "@/lib/config";
import { signIn } from "@/lib/auth-client";
import { fetchWithRetry } from "@/lib/auth/fetch-with-retry";
import { parseAuthError } from "@/lib/auth/auth-errors";
import { useAuth } from "@/lib/auth/auth-context";
import { OAuthButton } from "@/components/auth/OAuthButton";
import { LoginForm } from "@/components/auth/LoginForm";
import { AuthDivider } from "@/components/auth/AuthDivider";
import { AuthErrorBanner } from "@/components/auth/AuthErrorBanner";

export default function LoginPage(): ReactElement {
  return (
    <Suspense
      fallback={
        <AuthShell>
          <AuthCard>
            <div className="flex flex-col items-center gap-6">
              <AuthBrand />
              <div
                className="flex items-center justify-center py-8"
                role="status"
                aria-label="Loading authentication options"
              >
                <Loader2 className="h-8 w-8 animate-spin text-[#56a0ff]" aria-hidden="true" />
                <span className="sr-only">Loading authentication options</span>
              </div>
            </div>
          </AuthCard>
        </AuthShell>
      }
    >
      <LoginPageContent />
    </Suspense>
  );
}

function LoginPageContent(): ReactElement {
  const router = useRouter();
  const searchParams = useSearchParams();
  const { isAuthenticated, refreshSession } = useAuth();
  const [config, setConfig] = useState<AuthConfigResponse | null | undefined>(undefined);
  const [loadingConfig, setLoadingConfig] = useState(true);
  const [retryCount, setRetryCount] = useState(0);
  const [oauthLoading, setOauthLoading] = useState<string | null>(null);
  const [credentialsLoading, setCredentialsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [urlError, setUrlError] = useState<string | null>(null);

  /* Read ?error= query param on mount and map to PDA-friendly message */
  useEffect(() => {
    const errorCode = searchParams.get("error");
    if (errorCode) {
      const parsed = parseAuthError(errorCode);
      setUrlError(parsed.message);
      // Clean up the URL by removing the error param without triggering navigation
      const nextParams = new URLSearchParams(searchParams.toString());
      nextParams.delete("error");
      const query = nextParams.toString();
      router.replace(query ? `/login?${query}` : "/login");
    }
  }, [searchParams, router]);

  useEffect(() => {
    if (IS_MOCK_AUTH_MODE && isAuthenticated) {
      router.replace("/tasks");
    }
  }, [isAuthenticated, router]);

  useEffect(() => {
    if (IS_MOCK_AUTH_MODE) {
      setConfig({ providers: [] });
      setLoadingConfig(false);
      return;
    }

    let cancelled = false;

    async function fetchConfig(): Promise<void> {
      try {
        const response = await fetchWithRetry(`${API_BASE_URL}/auth/config`);
        if (!response.ok) {
          throw new Error("Failed to fetch auth config");
        }
        const data = (await response.json()) as AuthConfigResponse;
        if (!cancelled) {
          setConfig(data);
        }
      } catch (err: unknown) {
        if (!cancelled) {
          console.error("[Auth] Failed to load auth config:", err);
          setConfig(null);
          setUrlError(
            "Unable to load sign-in options. Please refresh the page or try again in a moment."
          );
        }
      } finally {
        if (!cancelled) {
          setLoadingConfig(false);
        }
      }
    }

    void fetchConfig();

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

  const oauthProviders: AuthProviderConfig[] =
    config?.providers.filter((p) => p.type === "oauth") ?? [];
  const credentialProviders: AuthProviderConfig[] =
    config?.providers.filter((p) => p.type === "credentials") ?? [];

  const hasOAuth = oauthProviders.length > 0;
  const hasCredentials = credentialProviders.length > 0;

  const handleOAuthLogin = useCallback((providerId: string): void => {
    setOauthLoading(providerId);
    setError(null);
    const callbackURL =
      typeof window !== "undefined" ? new URL("/", window.location.origin).toString() : "/";
    signIn
      .oauth2({ providerId, callbackURL })
      .then((result) => {
        // BetterAuth returns Data | Error union — check for error or missing redirect URL
        const hasError = "error" in result && result.error;
        const hasUrl = "data" in result && result.data?.url;
        if (hasError || !hasUrl) {
          const errObj = hasError ? result.error : null;
          const message =
            errObj && typeof errObj === "object" && "message" in errObj
              ? String(errObj.message)
              : "no redirect URL";
          console.error(`[Auth] OAuth sign-in failed for ${providerId}:`, message);
          setError("Unable to connect to the sign-in provider. Please try again in a moment.");
          setOauthLoading(null);
        }
        // If data.url exists, BetterAuth's client will redirect the browser automatically.
        // No need to reset loading — the page is navigating away.
      })
      .catch((err: unknown) => {
        const message = err instanceof Error ? err.message : String(err);
        console.error(`[Auth] OAuth sign-in initiation failed for ${providerId}:`, message);
        setError("Unable to connect to the sign-in provider. Please try again in a moment.");
        setOauthLoading(null);
      });
  }, []);

  const handleCredentialsLogin = useCallback(
    async (email: string, password: string): Promise<void> => {
      setCredentialsLoading(true);
      setError(null);

      try {
        const result = await signIn.email({ email, password });

        if (result.error) {
          const parsed = parseAuthError(
            result.error.message ? new Error(result.error.message) : result.error
          );
          setError(parsed.message);
        } else {
          router.push("/tasks");
        }
      } catch (err: unknown) {
        const parsed = parseAuthError(err);
        console.error("[Auth] Credentials sign-in failed:", err);
        setError(parsed.message);
      } finally {
        setCredentialsLoading(false);
      }
    },
    [router]
  );

  const handleRetry = useCallback((): void => {
    setConfig(undefined);
    setLoadingConfig(true);
    setUrlError(null);
    setError(null);
    setRetryCount((c) => c + 1);
  }, []);

  const handleMockLogin = useCallback(async (): Promise<void> => {
    setError(null);
    try {
      await refreshSession();
      router.push("/tasks");
    } catch (err: unknown) {
      const parsed = parseAuthError(err);
      setError(parsed.message);
    }
  }, [refreshSession, router]);

  if (IS_MOCK_AUTH_MODE) {
    return (
      <AuthShell>
        <AuthCard>
          <div className="flex flex-col items-center gap-6">
            <AuthBrand />
            <div className="text-center">
              <h1 className="text-xl font-bold tracking-tight sm:text-2xl">Command Center</h1>
              <p className="mt-1 text-sm text-[#5a6a87] dark:text-[#8f9db7]">
                Local mock auth mode is active
              </p>
            </div>
          </div>

          <div className="mt-6 space-y-4">
            <AuthStatusPill label="Mock mode" tone="warning" className="w-full justify-center" />
            {error && <AuthErrorBanner message={error} />}
            <button
              type="button"
              onClick={() => {
                void handleMockLogin();
              }}
              className="w-full inline-flex items-center justify-center gap-2 rounded-lg px-4 py-3 text-sm font-semibold text-white bg-[linear-gradient(135deg,#2f80ff,#8b5cf6)] transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-[#56a0ff]/60 hover:-translate-y-0.5 hover:shadow-[0_10px_30px_rgba(47,128,255,0.38)]"
              data-testid="mock-auth-login"
            >
              Continue with Mock Session
            </button>
          </div>
        </AuthCard>
      </AuthShell>
    );
  }

  return (
    <AuthShell>
      <AuthCard>
        <div className="flex flex-col items-center gap-6">
          <AuthBrand />
          <div className="text-center">
            <h1 className="text-xl font-bold tracking-tight sm:text-2xl">Command Center</h1>
            <p className="mt-1 text-sm text-[#5a6a87] dark:text-[#8f9db7]">
              Sign in to your orchestration platform
            </p>
          </div>
        </div>

        <div className="mt-6">
          {loadingConfig ? (
            <div
              className="flex items-center justify-center py-8"
              data-testid="loading-spinner"
              role="status"
              aria-label="Loading authentication options"
            >
              <Loader2 className="h-8 w-8 animate-spin text-[#56a0ff]" aria-hidden="true" />
              <span className="sr-only">Loading authentication options</span>
            </div>
          ) : config === null ? (
            <div className="space-y-4" data-testid="config-error-state">
              <AuthErrorBanner message={urlError ?? "Unable to load sign-in options."} />
              <div className="flex justify-center">
                <button
                  type="button"
                  onClick={handleRetry}
                  className="inline-flex items-center justify-center gap-2 rounded-lg px-4 py-2.5 text-sm font-semibold text-white bg-[linear-gradient(135deg,#2f80ff,#8b5cf6)] transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-[#56a0ff]/60 hover:-translate-y-0.5 hover:shadow-[0_10px_30px_rgba(47,128,255,0.38)]"
                >
                  Try again
                </button>
              </div>
            </div>
          ) : (
            <div className="space-y-0">
              {urlError && (
                <div className="mb-4">
                  <AuthErrorBanner
                    message={urlError}
                    onDismiss={(): void => {
                      setUrlError(null);
                    }}
                  />
                </div>
              )}

              {error && !hasCredentials && (
                <div className="mb-4">
                  <AuthErrorBanner
                    message={error}
                    onDismiss={(): void => {
                      setError(null);
                    }}
                  />
                </div>
              )}

              {hasCredentials && (
                <LoginForm
                  onSubmit={handleCredentialsLogin}
                  isLoading={credentialsLoading}
                  error={error}
                />
              )}

              {hasOAuth && hasCredentials && <AuthDivider />}

              {hasOAuth && (
                <div className="space-y-2">
                  {oauthProviders.map((provider) => (
                    <OAuthButton
                      key={provider.id}
                      providerName={provider.name}
                      providerId={provider.id}
                      onClick={(): void => {
                        handleOAuthLogin(provider.id);
                      }}
                      isLoading={oauthLoading === provider.id}
                      disabled={oauthLoading !== null && oauthLoading !== provider.id}
                    />
                  ))}
                </div>
              )}
            </div>
          )}
        </div>

        <div className="mt-6 flex justify-center">
          <AuthStatusPill label="Mosaic v0.0.20" tone="neutral" />
        </div>
      </AuthCard>
    </AuthShell>
  );
}
