import { useForm } from "@tanstack/react-form";
import { useCallback, useRef } from "react";
import { toast } from "sonner";

import { signInSchema, signUpSchema } from "../shared/forms";
import { authClient } from "./auth-client";
import { createSessionTokenResolver } from "./session-token-resolver";

interface AuthFormOptions {
  readonly onSuccess?: () => void;
}

export const useSignInForm = ({ onSuccess }: AuthFormOptions = {}) =>
  useForm({
    defaultValues: { email: "", password: "" },
    onSubmit: async ({ formApi, value }) => {
      await authClient.signIn.email(
        { email: value.email.trim(), password: value.password },
        {
          onError: ({ error }) => {
            toast.error(error.message || error.statusText);
          },
          onSuccess: () => {
            formApi.reset();
            toast.success("Signed in successfully");
            onSuccess?.();
          },
        }
      );
    },
    validators: { onSubmit: signInSchema },
  });

export const useSignUpForm = ({ onSuccess }: AuthFormOptions = {}) =>
  useForm({
    defaultValues: { confirmPassword: "", email: "", name: "", password: "" },
    onSubmit: async ({ formApi, value }) => {
      await authClient.signUp.email(
        {
          email: value.email.trim(),
          name: value.name.trim(),
          password: value.password,
        },
        {
          onError: ({ error }) => {
            toast.error(error.message || error.statusText);
          },
          onSuccess: () => {
            formApi.reset();
            toast.success("Account created successfully");
            onSuccess?.();
          },
        }
      );
    },
    validators: { onSubmit: signUpSchema },
  });

/**
 * Resolve the Better Auth/Convex JWT for the current signed-in session. The
 * installed `convex.token` plugin endpoint remains the token source; changing
 * or clearing the Better Auth session invalidates the cached value first.
 */
export const useConvexAccessToken = (): (() => Promise<string | null>) => {
  const { data: session } = authClient.useSession();
  const sessionId = session?.session.id ?? null;
  const resolverRef = useRef<ReturnType<
    typeof createSessionTokenResolver
  > | null>(null);
  resolverRef.current ??= createSessionTokenResolver();
  const resolveForSession = resolverRef.current;

  return useCallback(
    () =>
      resolveForSession(sessionId, async () => {
        const { data } = await authClient.convex.token({
          fetchOptions: { throw: false },
        });
        return data?.token ?? null;
      }),
    [resolveForSession, sessionId]
  );
};
