import { useCallback, useEffect, useMemo, useState } from "react";
import {
  extractAuthErrorMessage,
  getPasskeyModule,
  isPasskeyAvailableInBrowser,
  safeStringify,
  type AuthEnvironment,
  type AuthMode,
  type DemoPasskeyView,
} from "athena-auth-js";

type PasskeyHistoryRow = {
  action: string;
  status: string;
  detail: string;
};

type UsePasskeyWorkflowArgs = {
  mode: AuthMode;
  environment: AuthEnvironment;
  tenantId: string;
  tenantHeaderName: string;
  appendRow: (row: PasskeyHistoryRow) => void;
  setLastError: (value: unknown) => void;
  setLastResult: (value: unknown) => void;
  setMessage: (value: string) => void;
};

export function usePasskeyWorkflow({
  mode,
  environment,
  tenantId,
  tenantHeaderName,
  appendRow,
  setLastError,
  setLastResult,
  setMessage,
}: UsePasskeyWorkflowArgs) {
  const passkeyModule = useMemo(() => getPasskeyModule(), []);

  const [passkeys, setPasskeys] = useState<DemoPasskeyView[]>([]);
  const [passkeyName, setPasskeyName] = useState("Primary device");
  const [passkeyMessage, setPasskeyMessage] = useState<string | null>(null);
  const [passkeyLoadingAction, setPasskeyLoadingAction] = useState<string | null>(
    null,
  );
  const [passkeyRenameDrafts, setPasskeyRenameDrafts] = useState<
    Record<string, string>
  >({});
  const [passkeyAuthenticatorAttachment, setPasskeyAuthenticatorAttachment] =
    useState<"platform" | "cross-platform">("platform");
  const [passkeySupported, setPasskeySupported] = useState(false);

  const refreshPasskeys = useCallback(
    async ({ silent = false }: { silent?: boolean } = {}): Promise<void> => {
      if (mode === "forgot-password") return;
      if (!silent) {
        setPasskeyLoadingAction("refresh");
        setPasskeyMessage(null);
      }

      try {
        const result = await passkeyModule.listUserPasskeys();
        if (!result.ok) {
          if (result.status === 401) {
            setPasskeys([]);
            if (!silent) {
              setPasskeyMessage("Sign in first to manage passkeys.");
            }
            return;
          }
          throw new Error(
            result.message || `Failed to list passkeys (${result.status}).`,
          );
        }

        setPasskeys(result.passkeys);
        setPasskeyRenameDrafts((current) =>
          passkeyModule.buildRenameDrafts(result.passkeys, current),
        );

        if (!silent) {
          setPasskeyMessage(
            result.passkeys.length === 0
              ? "No passkeys registered for this account."
              : `Loaded ${result.passkeys.length} passkey${result.passkeys.length === 1 ? "" : "s"}.`,
          );
        }
      } catch (error) {
        if (!silent) {
          setPasskeyMessage(extractAuthErrorMessage(error));
        }
        setLastError(error);
        appendRow({
          action: "passkey_list",
          status: "api_error",
          detail: safeStringify(error),
        });
      } finally {
        if (!silent) {
          setPasskeyLoadingAction(null);
        }
      }
    },
    [appendRow, mode, passkeyModule, setLastError],
  );

  const registerPasskey = useCallback(async () => {
    if (mode === "forgot-password") return;
    setPasskeyLoadingAction("register");
    setPasskeyMessage(null);
    setLastError(null);

    try {
      const result = await passkeyModule.registerPasskey({
        passkeyName,
        authenticatorAttachment: passkeyAuthenticatorAttachment,
      });
      setLastResult(result);
      setMessage("Passkey registered successfully.");
      setPasskeyMessage("Passkey created on this device.");
      appendRow({
        action: "passkey_register",
        status: "ok",
        detail: safeStringify(result),
      });
      await refreshPasskeys({ silent: true });
    } catch (error) {
      setLastError(error);
      setPasskeyMessage(extractAuthErrorMessage(error));
      appendRow({
        action: "passkey_register",
        status: "api_error",
        detail: safeStringify(error),
      });
    } finally {
      setPasskeyLoadingAction(null);
    }
  }, [
    appendRow,
    mode,
    passkeyAuthenticatorAttachment,
    passkeyModule,
    passkeyName,
    refreshPasskeys,
    setLastError,
    setLastResult,
    setMessage,
  ]);

  const authenticateWithPasskey = useCallback(async () => {
    if (mode === "forgot-password") return;
    setPasskeyLoadingAction("authenticate");
    setPasskeyMessage(null);
    setLastError(null);

    try {
      const result = await passkeyModule.authenticateWithPasskey();
      setLastResult(result);
      setMessage("Signed in with passkey.");
      setPasskeyMessage("Passkey sign-in completed.");
      appendRow({
        action: "passkey_authenticate",
        status: "ok",
        detail: safeStringify(result),
      });
      await refreshPasskeys({ silent: true });
    } catch (error) {
      setLastError(error);
      setPasskeyMessage(extractAuthErrorMessage(error));
      appendRow({
        action: "passkey_authenticate",
        status: "api_error",
        detail: safeStringify(error),
      });
    } finally {
      setPasskeyLoadingAction(null);
    }
  }, [
    appendRow,
    mode,
    passkeyModule,
    refreshPasskeys,
    setLastError,
    setLastResult,
    setMessage,
  ]);

  const renamePasskey = useCallback(
    async (id: string) => {
      const nextName = passkeyRenameDrafts[id]?.trim();
      if (!nextName) {
        setPasskeyMessage("Passkey name cannot be empty.");
        return;
      }

      setPasskeyLoadingAction(`rename:${id}`);
      setPasskeyMessage(null);

      try {
        const result = await passkeyModule.renamePasskey(id, nextName);

        setPasskeyMessage("Passkey name updated.");
        appendRow({
          action: "passkey_rename",
          status: "ok",
          detail: safeStringify(result),
        });
        await refreshPasskeys({ silent: true });
      } catch (error) {
        setLastError(error);
        setPasskeyMessage(extractAuthErrorMessage(error));
        appendRow({
          action: "passkey_rename",
          status: "api_error",
          detail: safeStringify(error),
        });
      } finally {
        setPasskeyLoadingAction(null);
      }
    },
    [appendRow, passkeyModule, passkeyRenameDrafts, refreshPasskeys, setLastError],
  );

  const deletePasskey = useCallback(
    async (id: string) => {
      setPasskeyLoadingAction(`delete:${id}`);
      setPasskeyMessage(null);

      try {
        const result = await passkeyModule.deletePasskey(id);

        setPasskeyMessage("Passkey deleted.");
        appendRow({
          action: "passkey_delete",
          status: "ok",
          detail: safeStringify(result),
        });
        await refreshPasskeys({ silent: true });
      } catch (error) {
        setLastError(error);
        setPasskeyMessage(extractAuthErrorMessage(error));
        appendRow({
          action: "passkey_delete",
          status: "api_error",
          detail: safeStringify(error),
        });
      } finally {
        setPasskeyLoadingAction(null);
      }
    },
    [appendRow, passkeyModule, refreshPasskeys, setLastError],
  );

  const updateRenameDraft = useCallback((id: string, value: string) => {
    setPasskeyRenameDrafts((current) => ({
      ...current,
      [id]: value,
    }));
  }, []);

  useEffect(() => {
    setPasskeySupported(isPasskeyAvailableInBrowser());
  }, []);

  useEffect(() => {
    if (mode === "forgot-password") return;
    void refreshPasskeys({ silent: true });
  }, [
    environment,
    mode,
    refreshPasskeys,
    tenantHeaderName,
    tenantId,
  ]);

  return {
    passkeySupported,
    passkeyName,
    setPasskeyName,
    passkeyAuthenticatorAttachment,
    setPasskeyAuthenticatorAttachment,
    passkeys,
    passkeyRenameDrafts,
    passkeyLoadingAction,
    passkeyMessage,
    refreshPasskeys,
    registerPasskey,
    authenticateWithPasskey,
    renamePasskey,
    deletePasskey,
    updateRenameDraft,
  };
}
