import { api } from "@code/backend/convex/_generated/api";
import { useConvexAuth, useQuery } from "convex/react";
import { useEffect, useRef } from "react";

import { authClient } from "./auth-client";

export interface WebAuthUser {
  readonly id: string;
  readonly name: string;
  readonly email: string;
}

export type WebAuthState =
  | { readonly status: "loading" }
  | { readonly status: "unauthenticated" }
  | { readonly status: "authenticated"; readonly user: WebAuthUser }
  | { readonly status: "inconsistent" };

/**
 * Sign out of the web session. Clears the Better Auth session, which in turn
 * invalidates the cached Convex JWT (the session-token resolver keys on the
 * session id). Protected Convex queries after sign-out are denied.
 */
export const signOutWeb = async (): Promise<void> => {
  await authClient.signOut({ fetchOptions: { throw: false } });
};

/**
 * The single web-facing auth interface. Combines Convex auth state with the
 * normalized {@link api.auth.getCurrentUser} projection, skipping the user
 * query until Convex has authenticated. Reports `inconsistent` only when a JWT
 * is accepted but the Better Auth user row cannot be resolved.
 */
export const useWebAuth = (): WebAuthState => {
  const { isAuthenticated, isLoading } = useConvexAuth();

  // Skip the user query until Convex has accepted the JWT. This keeps the
  // status `loading` during token restoration and `unauthenticated` when no
  // session exists, without firing a query that would return null.
  const userQuery = useQuery(
    api.auth.getCurrentUser,
    isAuthenticated ? {} : "skip"
  );

  const signOutWebRef = useRef(signOutWeb);
  const inconsistent =
    isAuthenticated && userQuery !== undefined && userQuery === null;

  // If Convex accepted the JWT but the Better Auth user row cannot be resolved,
  // the session is inconsistent: sign out so the next sign-in starts clean.
  useEffect(() => {
    if (inconsistent) {
      void signOutWebRef.current();
    }
  }, [inconsistent]);

  if (isLoading) {
    return { status: "loading" };
  }

  if (!isAuthenticated) {
    return { status: "unauthenticated" };
  }

  if (userQuery === undefined) {
    return { status: "loading" };
  }

  if (userQuery === null) {
    return { status: "inconsistent" };
  }

  return {
    status: "authenticated",
    user: {
      email: userQuery.email,
      id: userQuery.id,
      name: userQuery.name,
    },
  };
};
