import { type ReactNode } from "react";
import { useCurrentUser } from "../store/index.tsx";
import { AccountIssueView } from "./AccountIssueView.tsx";
import { AlreadyLoggedInView } from "./AlreadyLoggedInView.tsx";
import { FailureFallbackView } from "./FailureFallbackView.tsx";
import { LoadingView } from "./LoadingView.tsx";
import { LoginView } from "./LoginView.tsx";
import { NoConnectionView } from "./NoConnectionView.tsx";
import type { AuthEventHandler, DefaultFormValues } from "./types.ts";
import { useFetchCurrentUser } from "./useFetchCurrentUser.tsx";
import { UserMismatchView } from "./UserMismatchView.tsx";

export type LoginCardProps = {
  /**
   * A description that will appear in the default login case (i.e. when an
   * unauthenticated user is prompted to log in).
   *
   * This should reinforce to the user the benefits that they are going to
   * get by signing in. Every app has slightly different capabilities, so this
   * should be tailored for each individual app.
   */
  description: ReactNode;

  /**
   * Default values for the login form.
   *
   * You might want to provide a value from history state or query param, so
   * that if a user jumps between multiple pages with email field, the email
   * address is maintained across these locations.
   */
  defaultValues?: DefaultFormValues;

  /**
   * Called when the login action succeeds.
   *
   * If no handler is provided, the component will will navigate to the
   * dashboard (as determined by `appConfig.hrefs.dashboard()` return value),
   * or a location provided in `redirectTo` query param if it is a valid
   * local path.
   */
  onLogin?: AuthEventHandler;
};

/**
 * Allows the user to log into Indie Tabletop Club.
 *
 * Will automatically use the `redirectTo` query param value as the redirect
 * location after successful login.
 *
 * Otherwise, the user will be redirected to the app's dashboard.
 */
export function LoginCard(props: LoginCardProps) {
  const currentUser = useCurrentUser();
  const { result, latestAttemptTs, reload } = useFetchCurrentUser();

  return result.unpack(
    (serverUser) => {
      if (currentUser && currentUser.id !== serverUser.id) {
        return (
          <UserMismatchView
            serverUser={serverUser}
            localUser={currentUser}
            reload={reload}
          />
        );
      }

      return <AlreadyLoggedInView currentUser={serverUser} reload={reload} />;
    },

    (failure) => {
      if (failure.type === "API_ERROR") {
        if (failure.code === 401) {
          return (
            <LoginView {...props} currentUser={currentUser} reload={reload} />
          );
        }

        if (failure.code === 404) {
          return <AccountIssueView reload={reload} />;
        }
      }

      if (failure.type === "NETWORK_ERROR") {
        return (
          <NoConnectionView
            latestAttemptTs={latestAttemptTs}
            onRetry={() => reload()}
          />
        );
      }

      return <FailureFallbackView />;
    },

    () => {
      return <LoadingView />;
    },
  );
}
