"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import dynamic from "next/dynamic";
import NextLink from "next/link";
import {
  DEFAULT_AUTH_TENANT_HEADER,
  TRUSTED_ORIGINS_STORAGE_KEY,
  addOriginToTrustedOrigins,
  authSubmitSuccessText,
  buildAuthSubmitFallbackPath,
  buildAuthSubmitFallbackPayload,
  buildTrustedOriginsEnvLine,
  callAuthEndpoint,
  extractAuthErrorMessage,
  getAuthTargetForEnvironment,
  isRecord,
  isRuntimeInterferenceError,
  parseRuntimeDiagnosticsConfig,
  readTenantSelectionFromStorage,
  runtimeConfigErrorMessage,
  safeStringify,
  validateAuthForm,
  writeTenantSelectionToStorage,
  type AuthEnvironment,
  type AuthFormErrors,
  type AuthMode,
} from "athena-auth-js";
import { createAuthClient } from "../lib/auth-client";
import { AuthDiagnostics } from "./auth-diagnostics";
import { AuthEnvironmentControls } from "./auth/auth-environment-controls";
import { AuthFeedbackStack } from "./auth/auth-feedback-stack";
import { AuthNavigationLinks } from "./auth/auth-navigation-links";
import { PasskeyControls } from "./auth/passkey-controls";
import { AuthResultPanels } from "./auth/auth-result-panels";
import { AuthSubmitForm } from "./auth/auth-submit-form";
import { usePasskeyWorkflow } from "./auth/use-passkey-workflow";
import { Badge } from "./ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
import type { ComboOption } from "./ui/combobox";
import { SOCIAL_PROVIDER_IDS } from "../lib/social-auth-config";
import type {
  SocialProviderConfig,
  SocialProviderId,
} from "../lib/social-auth-config";

const HistoryTable = dynamic(
  () => import("./history-table").then((m) => m.HistoryTable),
  { ssr: false },
);

type RowItem = { id: string; action: string; status: string; detail: string };

const emailOptions: ComboOption[] = [
  { value: "floris@xylex.group", label: "floris@xylex.group" },
  { value: "demo@example.com", label: "demo@example.com" },
  { value: "admin@example.com", label: "admin@example.com" },
];

const MODE_LINKS: Array<{ mode: AuthMode; href: string; label: string }> = [
  { mode: "sign-in", href: "/login", label: "Sign in" },
  { mode: "sign-up", href: "/sign-up", label: "Create account" },
  { mode: "forgot-password", href: "/forgot-password", label: "Forgot password" },
];

export function AuthCard({ mode }: { mode: AuthMode }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [name, setName] = useState("");
  const [errors, setErrors] = useState<AuthFormErrors>({});
  const [message, setMessage] = useState<string | null>(null);
  const [forgotAccepted, setForgotAccepted] = useState<boolean | null>(null);
  const [lastForgotEmail, setLastForgotEmail] = useState("");
  const [resendLoading, setResendLoading] = useState(false);
  const [resendMessage, setResendMessage] = useState<string | null>(null);
  const [lastResult, setLastResult] = useState<unknown>(null);
  const [lastError, setLastError] = useState<unknown>(null);
  const [rows, setRows] = useState<RowItem[]>([]);
  const [environment, setEnvironment] = useState<AuthEnvironment>("proxy");
  const [tenantId, setTenantId] = useState("");
  const [tenantHeaderName, setTenantHeaderName] = useState(
    DEFAULT_AUTH_TENANT_HEADER,
  );
  const [tenantSelectionMessage, setTenantSelectionMessage] = useState<
    string | null
  >(null);
  const [trustedOriginsConfig, setTrustedOriginsConfig] = useState("");
  const [trustedOriginsLoading, setTrustedOriginsLoading] = useState(false);
  const [trustedOriginsMessage, setTrustedOriginsMessage] = useState<
    string | null
  >(null);
  const [runtimeFallbackNotice, setRuntimeFallbackNotice] = useState<
    string | null
  >(null);
  const [loading, setLoading] = useState(false);
  const [socialProviders, setSocialProviders] = useState<SocialProviderConfig[]>(
    [],
  );
  const [socialLoadingProvider, setSocialLoadingProvider] =
    useState<SocialProviderId | null>(null);
  const [socialCallbackPath, setSocialCallbackPath] = useState("/session");

  const title =
    mode === "sign-in"
      ? "Sign in"
      : mode === "sign-up"
        ? "Create account"
        : "Forgot password";
  const modeDescription =
    mode === "sign-in"
      ? "Use email/password, social providers, or a registered passkey."
      : mode === "sign-up"
        ? "Create a new account and immediately register a passkey for passwordless sign-in."
        : "Request a reset link for your account email.";

  const appendRow = useCallback((row: Omit<RowItem, "id">) => {
    setRows((prev) =>
      [{ id: crypto.randomUUID(), ...row }, ...prev].slice(0, 8),
    );
  }, []);

  const passkey = usePasskeyWorkflow({
    mode,
    environment,
    tenantId,
    tenantHeaderName,
    appendRow,
    setLastError,
    setLastResult,
    setMessage: (value) => setMessage(value),
  });

  const currentTarget = useMemo(() => getAuthTargetForEnvironment(environment), [environment]);

  const authClient = useMemo(
    () => createAuthClient({ authApiOrigin: currentTarget }),
    [currentTarget],
  );

  useEffect(() => {
    if (typeof window === "undefined") return;
    const saved = window.localStorage.getItem(TRUSTED_ORIGINS_STORAGE_KEY);
    if (saved) setTrustedOriginsConfig(saved);
    const tenantSelection = readTenantSelectionFromStorage();
    setTenantId(tenantSelection.tenantId);
    setTenantHeaderName(tenantSelection.headerName);
  }, []);

  useEffect(() => {
    if (typeof window === "undefined") return;
    window.localStorage.setItem(
      TRUSTED_ORIGINS_STORAGE_KEY,
      trustedOriginsConfig,
    );
  }, [trustedOriginsConfig]);

  const addCurrentOrigin = () => {
    if (typeof window === "undefined") return;
    const current = window.location.origin;
    setTrustedOriginsConfig(
      addOriginToTrustedOrigins(trustedOriginsConfig, current),
    );
    setTrustedOriginsMessage(null);
  };

  const loadRuntimeConfig = async () => {
    setTrustedOriginsLoading(true);
    setTrustedOriginsMessage(null);
    try {
      const response = await fetch("/api/auth/diagnostics", {
        method: "GET",
        cache: "no-store",
      });
      const payload = (await response.json().catch(() => ({}))) as unknown;

      if (!response.ok) {
        setTrustedOriginsMessage(runtimeConfigErrorMessage(payload, response.status));
        return;
      }

      const parsedConfig = parseRuntimeDiagnosticsConfig(
        payload,
        SOCIAL_PROVIDER_IDS,
      );
      const trustedOriginsRaw = parsedConfig.trustedOriginsRaw;
      setTrustedOriginsConfig(trustedOriginsRaw);
      setTrustedOriginsMessage(
        trustedOriginsRaw
          ? "Loaded TRUSTED_ORIGINS from diagnostics endpoint."
          : "Diagnostics endpoint returned no TRUSTED_ORIGINS value.",
      );
      setSocialProviders(parsedConfig.social.providers);
      setSocialCallbackPath(parsedConfig.social.callbackPath);
    } catch (error) {
      setTrustedOriginsMessage(
        error instanceof Error ? error.message : "Runtime config request failed.",
      );
    } finally {
      setTrustedOriginsLoading(false);
    }
  };

  const copyTrustedOriginsEnv = async () => {
    const line = buildTrustedOriginsEnvLine(trustedOriginsConfig);
    try {
      await navigator.clipboard.writeText(line);
      setTrustedOriginsMessage("Copied TRUSTED_ORIGINS line.");
    } catch {
      setTrustedOriginsMessage("Copy failed. Copy manually from the field.");
    }
  };

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

    const loadSocialRuntime = async () => {
      try {
        const response = await fetch("/api/auth/diagnostics", {
          method: "GET",
          cache: "no-store",
        });
        const payload = (await response.json().catch(() => ({}))) as unknown;
        if (!response.ok || cancelled) return;

        const parsed = parseRuntimeDiagnosticsConfig(payload, SOCIAL_PROVIDER_IDS);
        if (cancelled) return;
        setSocialProviders(parsed.social.providers);
        setSocialCallbackPath(parsed.social.callbackPath);
      } catch {
        if (!cancelled) {
          setSocialProviders([]);
          setSocialCallbackPath("/session");
        }
      }
    };

    void loadSocialRuntime();

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

  const applyTenantSelection = () => {
    writeTenantSelectionToStorage({
      tenantId,
      headerName: tenantHeaderName,
    });
    if (tenantId.trim()) {
      setTenantSelectionMessage(
        `Tenant routing active: ${tenantHeaderName.trim() || DEFAULT_AUTH_TENANT_HEADER}=${tenantId.trim()}`,
      );
    } else {
      setTenantSelectionMessage("Tenant routing cleared; default tenant will be used.");
    }
  };

  const executeDirectFallback = async ({
    action,
    path,
    payload,
    primaryError,
    successText,
    feedback,
    onSuccess,
    onFailure,
  }: {
    action: string;
    path: string;
    payload: Record<string, unknown>;
    primaryError: string;
    successText: string;
    feedback: "submit" | "resend";
    onSuccess?: () => void;
    onFailure?: () => void;
  }): Promise<void> => {
    const fallback = await callAuthEndpoint(path, {
      method: "POST",
      body: JSON.stringify(payload),
    });

    if (fallback.ok) {
      onSuccess?.();
      if (feedback === "submit") {
        setMessage(successText);
      } else {
        setResendMessage(successText);
      }
      setRuntimeFallbackNotice(
        "Browser runtime interference detected. Request completed with direct API fallback.",
      );
      setLastResult(fallback.body ?? fallback);
      setLastError({
        primaryError,
        fallbackTransport: "direct_fetch",
        fallbackStatus: fallback.status,
      });
      appendRow({
        action,
        status: "ok_fallback",
        detail: safeStringify({ primaryError, fallback: fallback.body ?? fallback }),
      });
      return;
    }

    onFailure?.();
    setRuntimeFallbackNotice(
      "Browser runtime interference detected. Direct fallback also failed; check response details below.",
    );
    setLastError({
      primaryError,
      fallback,
    });
    if (feedback === "submit") {
      setMessage(fallback.message || "Request failed after direct API fallback attempt.");
    } else {
      setResendMessage(
        fallback.message || "Resend request failed after direct API fallback attempt.",
      );
    }
    appendRow({
      action,
      status: "fallback_error",
      detail: safeStringify({ primaryError, fallback }),
    });
  };

  const onSubmit = async (event: React.FormEvent) => {
    event.preventDefault();
    setMessage(null);
    setResendMessage(null);
    setLastResult(null);
    setLastError(null);
    setRuntimeFallbackNotice(null);

    const nextErrors = validateAuthForm(mode, email, password, name);
    setErrors(nextErrors);
    if (Object.keys(nextErrors).length > 0) {
      appendRow({
        action: mode,
        status: "validation_error",
        detail: safeStringify(nextErrors),
      });
      return;
    }

    setLoading(true);
    try {
      if (mode === "sign-in") {
        const result = await authClient.signIn.email({ email, password });
        if (result.error) throw result.error;
        setLastResult(result.data ?? result);
        setMessage("Signed in successfully.");
        appendRow({
          action: "sign_in",
          status: "ok",
          detail: safeStringify(result.data ?? result),
        });
      }

      if (mode === "sign-up") {
        const result = await authClient.signUp.email({ email, password, name });
        if (result.error) throw result.error;
        setLastResult(result.data ?? result);
        setMessage("Account created.");
        appendRow({
          action: "sign_up",
          status: "ok",
          detail: safeStringify(result.data ?? result),
        });
      }

      if (mode === "forgot-password") {
        const result = await authClient.requestPasswordReset({
          email,
          redirectTo: `${window.location.origin}/reset-password`,
        });
        if (result.error) throw result.error;
        setLastResult(result.data ?? result);
        setForgotAccepted(true);
        setLastForgotEmail(email);
        setMessage("Reset requested. API accepted the request.");
        appendRow({
          action: "request_password_reset",
          status: "ok",
          detail: safeStringify(result.data ?? result),
        });
      }
    } catch (error) {
      const mapped = extractAuthErrorMessage(error);
      if (isRuntimeInterferenceError(mapped)) {
        const submitPath = buildAuthSubmitFallbackPath(mode);
        const submitPayload = buildAuthSubmitFallbackPayload(mode, {
          email,
          password,
          name,
          origin: window.location.origin,
        });
        await executeDirectFallback({
          action: mode,
          path: submitPath,
          payload: submitPayload,
          primaryError: mapped,
          successText: authSubmitSuccessText(mode),
          feedback: "submit",
          onSuccess:
            mode === "forgot-password"
              ? () => {
                  setForgotAccepted(true);
                  setLastForgotEmail(email);
                }
              : undefined,
          onFailure:
            mode === "forgot-password"
              ? () => {
                  setForgotAccepted(false);
                }
              : undefined,
        });
        return;
      }

      if (mode === "forgot-password") setForgotAccepted(false);
      setLastError(error);
      setMessage(mapped);
      appendRow({
        action: mode,
        status: "api_error",
        detail: safeStringify(error),
      });
    } finally {
      setLoading(false);
    }
  };

  const resendVerification = async () => {
    if (!email) {
      setErrors((prev) => ({
        ...prev,
        email: "Email is required to resend verification",
      }));
      return;
    }

    setResendMessage(null);
    setLastError(null);
    setRuntimeFallbackNotice(null);
    setResendLoading(true);
    try {
      const result = await authClient.sendVerificationEmail({
        email,
        callbackURL: `${window.location.origin}/session`,
      });
      if (result.error) throw result.error;
      setLastResult(result.data ?? result);
      setResendMessage("Verification email resend request accepted.");
      appendRow({
        action: "resend_verification",
        status: "ok",
        detail: safeStringify(result.data ?? result),
      });
    } catch (error) {
      const mapped = extractAuthErrorMessage(error);
      if (isRuntimeInterferenceError(mapped)) {
        await executeDirectFallback({
          action: "resend_verification",
          path: "/send-verification-email",
          payload: {
            email,
            callbackURL: `${window.location.origin}/session`,
          },
          primaryError: mapped,
          successText: "Verification email resend request accepted.",
          feedback: "resend",
        });
        return;
      }

      setLastError(error);
      setResendMessage(mapped);
      appendRow({
        action: "resend_verification",
        status: "api_error",
        detail: safeStringify(error),
      });
    } finally {
      setResendLoading(false);
    }
  };

  const signInWithSocial = async (provider: SocialProviderId) => {
    if (mode === "forgot-password") return;

    setMessage(null);
    setResendMessage(null);
    setLastResult(null);
    setLastError(null);
    setRuntimeFallbackNotice(null);
    setSocialLoadingProvider(provider);

    const callbackURL =
      typeof window !== "undefined"
        ? `${window.location.origin}${socialCallbackPath}`
        : socialCallbackPath;

    try {
      const result = await authClient.signIn.social({
        provider,
        callbackURL,
        disableRedirect: true,
      });

      if (result.error) throw result.error;

      const payload = result.data;
      const redirectUrl =
        isRecord(payload) && typeof payload.url === "string"
          ? payload.url
          : null;

      if (!redirectUrl) {
        throw new Error("Social sign-in did not return a redirect URL.");
      }

      setLastResult(payload ?? result);
      appendRow({
        action: `social_sign_in:${provider}`,
        status: "redirect",
        detail: safeStringify(payload ?? result),
      });
      window.location.assign(redirectUrl);
    } catch (error) {
      const mapped = extractAuthErrorMessage(error);
      if (isRuntimeInterferenceError(mapped) && environment === "proxy") {
        const fallback = await callAuthEndpoint<{ url?: string; redirect?: boolean }>(
          "/sign-in/social",
          {
            method: "POST",
            body: JSON.stringify({ provider, callbackURL }),
          },
        );

        const fallbackBody = isRecord(fallback.body) ? fallback.body : null;
        const fallbackUrl =
          fallbackBody && typeof fallbackBody.url === "string"
            ? fallbackBody.url
            : null;

        if (fallback.ok && fallbackUrl) {
          setRuntimeFallbackNotice(
            "Browser runtime interference detected. Social login resumed with direct API fallback.",
          );
          setLastResult(fallback.body ?? fallback);
          appendRow({
            action: `social_sign_in:${provider}`,
            status: "redirect_fallback",
            detail: safeStringify(fallback.body ?? fallback),
          });
          window.location.assign(fallbackUrl);
          return;
        }

        setRuntimeFallbackNotice(
          "Browser runtime interference detected. Social fallback failed; check diagnostics.",
        );
        setLastError({
          primaryError: mapped,
          fallback,
        });
        setMessage(
          fallback.message || "Social sign-in failed after direct API fallback attempt.",
        );
        appendRow({
          action: `social_sign_in:${provider}`,
          status: "fallback_error",
          detail: safeStringify({ primaryError: mapped, fallback }),
        });
        return;
      }

      setLastError(error);
      setMessage(mapped);
      appendRow({
        action: `social_sign_in:${provider}`,
        status: "api_error",
        detail: safeStringify(error),
      });
    } finally {
      setSocialLoadingProvider(null);
    }
  };

  const userLike =
    (lastResult &&
      typeof lastResult === "object" &&
      "user" in (lastResult as Record<string, unknown>) &&
      (lastResult as Record<string, unknown>).user) ||
    null;

  const emailVerified =
    userLike &&
    typeof userLike === "object" &&
    "emailVerified" in (userLike as Record<string, unknown>)
      ? Boolean((userLike as Record<string, unknown>).emailVerified)
      : null;

  return (
    <main className="mx-auto w-full max-w-[1520px] px-4 py-6 md:px-6">
      <Card className="overflow-hidden border-slate-200/90 bg-white/90 shadow-[0_24px_80px_-42px_rgba(15,23,42,0.45)]">
        <CardHeader className="gap-4 border-b border-slate-200/70 bg-gradient-to-r from-slate-50 via-white to-cyan-50/60">
          <div className="flex flex-wrap items-start justify-between gap-3">
            <div className="space-y-2">
              <p className="text-xs font-semibold uppercase tracking-[0.18em] text-slate-500">
                Athena Auth Demo
              </p>
              <CardTitle className="text-2xl text-slate-900">{title}</CardTitle>
              <p className="max-w-3xl text-sm text-slate-600">{modeDescription}</p>
            </div>
            {mode !== "forgot-password" ? (
              <Badge variant={passkey.passkeySupported ? "success" : "warning"}>
                {passkey.passkeySupported ? "Passkey ready" : "Passkey unavailable"}
              </Badge>
            ) : null}
          </div>
          <div className="flex flex-wrap gap-2">
            {MODE_LINKS.map((link) => (
              <NextLink
                key={link.href}
                href={link.href}
                className={[
                  "rounded-full border px-3 py-1 text-sm transition-colors",
                  link.mode === mode
                    ? "border-slate-900 bg-slate-900 text-white"
                    : "border-slate-300 bg-white text-slate-700 hover:bg-slate-100",
                ].join(" ")}
              >
                {link.label}
              </NextLink>
            ))}
          </div>
        </CardHeader>

        <CardContent className="grid gap-5 p-4 pt-4 lg:grid-cols-[minmax(0,1fr)_minmax(320px,460px)] lg:p-6 lg:pt-6">
          <section className="grid content-start gap-4">
            <AuthSubmitForm
              mode={mode}
              email={email}
              password={password}
              name={name}
              errors={errors}
              loading={loading}
              resendLoading={resendLoading}
              socialProviders={socialProviders}
              socialLoadingProvider={socialLoadingProvider}
              onEmailChange={setEmail}
              onPasswordChange={setPassword}
              onNameChange={setName}
              onSubmit={(event) => void onSubmit(event)}
              onResendVerification={() => void resendVerification()}
              onSocialSignIn={(provider) => void signInWithSocial(provider)}
            />
            <PasskeyControls
              mode={mode}
              passkeySupported={passkey.passkeySupported}
              passkeyName={passkey.passkeyName}
              onPasskeyNameChange={passkey.setPasskeyName}
              authenticatorAttachment={passkey.passkeyAuthenticatorAttachment}
              onAuthenticatorAttachmentChange={passkey.setPasskeyAuthenticatorAttachment}
              passkeys={passkey.passkeys}
              passkeyRenameDrafts={passkey.passkeyRenameDrafts}
              passkeyLoadingAction={passkey.passkeyLoadingAction}
              passkeyMessage={passkey.passkeyMessage}
              onRegisterPasskey={() => void passkey.registerPasskey()}
              onAuthenticateWithPasskey={() => void passkey.authenticateWithPasskey()}
              onRefreshPasskeys={() => void passkey.refreshPasskeys()}
              onPasskeyRenameDraftChange={passkey.updateRenameDraft}
              onRenamePasskey={(id) => void passkey.renamePasskey(id)}
              onDeletePasskey={(id) => void passkey.deletePasskey(id)}
            />
            <AuthFeedbackStack
              runtimeFallbackNotice={runtimeFallbackNotice}
              message={message}
              resendMessage={resendMessage}
            />
            <AuthNavigationLinks />
          </section>

          <aside className="grid content-start gap-4">
            <AuthEnvironmentControls
              environment={environment}
              onEnvironmentChange={setEnvironment}
              email={email}
              onEmailChange={(value) => {
                setEmail(value);
                setErrors((prev) => ({ ...prev, email: "" }));
              }}
              emailOptions={emailOptions}
              trustedOriginsConfig={trustedOriginsConfig}
              onTrustedOriginsConfigChange={(value) => {
                setTrustedOriginsConfig(value);
                setTrustedOriginsMessage(null);
              }}
              trustedOriginsMessage={trustedOriginsMessage}
              trustedOriginsLoading={trustedOriginsLoading}
              onLoadRuntimeConfig={() => void loadRuntimeConfig()}
              onAddCurrentOrigin={addCurrentOrigin}
              onCopyTrustedOriginsEnv={() => void copyTrustedOriginsEnv()}
              tenantId={tenantId}
              onTenantIdChange={setTenantId}
              tenantHeaderName={tenantHeaderName}
              onTenantHeaderNameChange={setTenantHeaderName}
              onApplyTenantSelection={applyTenantSelection}
              tenantSelectionMessage={tenantSelectionMessage}
            />
            <AuthResultPanels
              currentTarget={currentTarget}
              emailVerified={emailVerified}
              email={email}
              lastResult={lastResult}
              lastError={lastError}
            />
            <section className="grid gap-2 rounded-2xl border border-slate-200/70 bg-white/95 p-4 shadow-sm">
              <strong className="text-sm text-slate-800">Request history</strong>
              <HistoryTable rows={rows} />
            </section>
          </aside>
        </CardContent>
      </Card>

      <AuthDiagnostics
        lastForgotEmail={lastForgotEmail}
        forgotRequestAccepted={forgotAccepted}
      />
    </main>
  );
}
