import {
  IonContent,
  IonRefresher,
  IonRefresherContent,
  IonSpinner,
  useIonAlert,
} from "@ionic/react";
import { useCallback, useEffect, useEffectEvent, useState } from "react";
import { GetPersonDetailsResponse, NotFoundError } from "threadiverse";

import Profile from "#/features/user/Profile";
import { getUser } from "#/features/user/userSlice";
import { useBuildGeneralBrowseLink } from "#/helpers/routes";
import { useOptimizedIonRouter } from "#/helpers/useOptimizedIonRouter";
import FeedContent from "#/routes/pages/shared/FeedContent";
import { useAppDispatch } from "#/store";

import sharedStyles from "#/features/shared/shared.module.css";

interface AsyncProfileProps {
  handle: string;
}

export default function AsyncProfile({ handle }: AsyncProfileProps) {
  const buildGeneralBrowseLink = useBuildGeneralBrowseLink();
  const dispatch = useAppDispatch();
  const [person, setPerson] = useState<
    GetPersonDetailsResponse | "failed" | undefined
  >();
  const router = useOptimizedIonRouter();
  const [present] = useIonAlert();

  const load = useCallback(
    async (signal?: AbortSignal) => {
      let data;

      try {
        data = await dispatch(getUser(handle, signal));
      } catch (error) {
        if (signal?.aborted) throw error;

        if (error instanceof NotFoundError) {
          await present(`Huh, u/${handle} doesn't exist. Mysterious...`);

          if (router.canGoBack()) {
            router.goBack();
          } else {
            router.push(buildGeneralBrowseLink("/"));
          }

          throw error;
        }

        setPerson("failed");

        throw error;
      }

      setPerson(data);
    },
    [buildGeneralBrowseLink, dispatch, handle, present, router],
  );

  const loadEvent = useEffectEvent(load);

  useEffect(() => {
    const abortController = new AbortController();

    // See https://react.dev/learn/you-might-not-need-an-effect#fetching-data
    // eslint-disable-next-line react-hooks/set-state-in-effect
    if (handle) loadEvent(abortController.signal);

    return () => abortController.abort();
  }, [handle]);

  if (!person)
    return (
      <FeedContent color="light-bg">
        <IonSpinner className={sharedStyles.pageSpinner} />
      </FeedContent>
    );

  if (person === "failed")
    return (
      <IonContent scrollY color="light-bg">
        <IonRefresher
          slot="fixed"
          onIonRefresh={async (e) => {
            try {
              await load();
            } finally {
              e.detail.complete();
            }
          }}
        >
          <IonRefresherContent />
        </IonRefresher>
        <div className={sharedStyles.pageFailedMessage}>
          failed to load user profile 😢
        </div>
      </IonContent>
    );

  return (
    <FeedContent color="light-bg">
      <Profile person={person.person_view} onPull={load} />
    </FeedContent>
  );
}
