import { TextUtil } from "@greatness/util";
import { useEffect, useRef } from "react";

import createUseStyles from "../theme/createUseStyles";

import Spinner from "./Spinner";
import { cn } from "../util/cn";

const useStyles = createUseStyles<{ containerHeight?: number | string }>({
  container: {
    height: ({ containerHeight }) =>
      containerHeight !== undefined
        ? typeof containerHeight === "number"
          ? `${containerHeight}px`
          : containerHeight
        : "100%",
  },
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ScrollIntoViewRef = React.RefObject<HTMLDivElement | null> | null;
type ScrollIntoViewOptions = {
  behavior?: ScrollBehavior;
  block?: ScrollLogicalPosition;
  inline?: ScrollLogicalPosition;
  narrow?: boolean;
} | null;
type ScrollIntoViewFunction = (
  ref?: ScrollIntoViewRef,
  options?: ScrollIntoViewOptions,
) => void;

const scrollIntoView: ScrollIntoViewFunction = (ref, options) => {
  if (!ref?.current) {
    return;
  }

  let scrollOptions = options;
  const isWide = window.innerWidth > 768;
  if (!scrollOptions || (options?.narrow === true && isWide)) {
    scrollOptions = {
      behavior: "smooth",
    };
    if (isWide) {
      scrollOptions.block = "center";
    }
  }
  ref.current.scrollIntoView(scrollOptions);
};

export default function LoadingPage({
  className,
  isLoading = true,
  children,
  containerHeight,
  scroll,
  persist = false,
  label,
}: {
  children?: React.ReactNode;
  className?: string;
  containerHeight?: number | string;
  isLoading?: boolean;
  label?: string;
  persist?: boolean;
  scroll?: boolean;
}) {
  const ref = useRef<HTMLDivElement>(null);
  const classes = useStyles({ containerHeight });

  useEffect(() => {
    if (isLoading) {
      if (scroll === true) {
        scrollIntoView(ref);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isLoading, scroll]);

  const isAnimationFinished = !isLoading;
  if (isAnimationFinished && !persist) {
    return <>{children}</>;
  }

  return (
    <>
      <div
        className={cn(
          "flex flex-col items-center bg-white w-auto p-xs",
          classes.container,
          className,
          {
            ["hidden"]: isAnimationFinished,
          }
        )}
        ref={ref}
      >
        <Spinner />
        {!TextUtil.isEmpty(label) && (
          <div className="pb-m pt-0 text-center word-break-break-word">
            <h4>{label!}</h4>
          </div>
        )}
      </div>
      {persist && (
        <div className={isAnimationFinished ? "persist" : "hidden"}>
          {children}
        </div>
      )}
    </>
  );
}
