import { useState, type ReactNode } from "react";
import { ModalDialog } from "../ModalDialog/index.tsx";
import { useCurrentUser } from "../store/index.tsx";
import { AccountIssueView } from "./AccountIssueView.tsx";
import { LoginView } from "./LoginView.tsx";
import { useFetchCurrentUser } from "./useFetchCurrentUser.tsx";
import { UserMismatchView } from "./UserMismatchView.tsx";
import { VerifyAccountView } from "./VerifyPage.tsx";

type CurrentUserFetcherProps = {
  children: ReactNode;
};

/**
 * Fetches fresh current user data if a local user exists in the app store.
 *
 * This component uses the Indie Tabletop Client under the hood, so if new
 * data is successfully fetched, the onCurrentUser callback will be invoked,
 * and it is up to the configuration of the client to store the data.
 *
 * Importantly, this component also handles the various user account issues
 * that we could run into: expired session, user mismatch and account deletion.
 *
 * All other errors are ignored. This allows users to use the app in offline
 * mode, and doesn't interrupt their session if some unexpected error happens,
 * which they cannot do anything about anyways.
 */
export function CurrentUserFetcher(props: CurrentUserFetcherProps) {
  const { children } = props;
  const localUser = useCurrentUser();
  const [isOpen, setOpen] = useState(true);

  const { result, reload } = useFetchCurrentUser({
    // We only want to fetch the current user if they exist in the store, i.e.
    // they have logged into the app previously.
    performFetch: !!localUser,

    // If we are performing a fetch, we want to make sure that it is up to date
    // every time the user focuses the window.
    revalidateOnFocus: true,
  });

  if (result.isFailure && result.failure.type === "API_ERROR") {
    // The user's session has expired. They should be prompted to
    // re-authenticate, as any syncing attemps will fail.
    if (result.failure.code === 401) {
      return (
        <>
          <ModalDialog size="large" open>
            <LoginView
              currentUser={localUser}
              onLogin={() => reload()}
              description={undefined}
              reload={reload}
            />
          </ModalDialog>
          {children}
        </>
      );
    }

    if (result.failure.code === 404) {
      // The user account is not found. The user might have been deleted.
      // The user should be notified and instructed to log out, as many
      // interactions acrosss the app will be broken.
      return (
        <>
          <ModalDialog size="large" open>
            <AccountIssueView reload={reload} />
          </ModalDialog>

          {children}
        </>
      );
    }
  }

  if (localUser && result.isSuccess) {
    const serverUser = result.value;

    // The cookie (server) user and the user in local storage are a different
    // user. The current user needs to decide which account to use.
    if (serverUser.id !== localUser.id) {
      return (
        <>
          <ModalDialog size="large" open>
            <UserMismatchView
              serverUser={result.value}
              localUser={localUser}
              reload={reload}
            />
          </ModalDialog>

          {children}
        </>
      );
    }

    if (!serverUser.isVerified) {
      return (
        <>
          <ModalDialog size="large" open={isOpen}>
            <VerifyAccountView
              currentUser={serverUser}
              onClose={() => setOpen(false)}
              reload={reload}
            />
          </ModalDialog>

          {children}
        </>
      );
    }
  }

  // In all other cases we simply render the children
  return <>{children}</>;
}
