import clsx from "clsx";
import { Fragment, useEffect, useState, type ReactNode } from "react";
import { HelmetProvider } from "react-helmet-async";
import { Link, Outlet, ScrollRestoration, useLocation } from "react-router";
import {
  ARTISTS_OR_CREATORS,
  BANNER_GLOBAL,
  DISABLE_DMS,
  DISABLE_FAQ,
  DISABLE_FILEHAUS,
  SIDEBAR_ITEMS,
} from "#env/env-vars";
import {
  createAPIDocumentationPageURL,
  createAccountFavoriteProfilesPageURL,
  createLoginPageURL,
  createLogoutPageURL,
  createRegistrationPageURL,
} from "#lib/urls";
import { fetchHasPendingDMs } from "#api/dms";
import { getLocalStorageItem, setLocalStorageItem } from "#storage/local";
import { ClientProvider } from "#hooks";
import { LoadingIcon } from "#components/loading";
import { isRegisteredAccount } from "#entities/account";
import { NavEntry, NavItem, NavList, type INavItem } from "./sidebar";
import { GlobalFooter } from "./footer";

interface ILayoutProps {
  children: ReactNode;
}

interface IGlobalBodyProps extends ILayoutProps {
  isSidebarClosed: boolean;
  closeSidebar: (_?: any, setState?: boolean) => void;
}

interface IGlobalSidebarProps {
  isSidebarClosed: boolean;
  closeSidebar: (_?: any, setState?: boolean) => void;
}

interface IHeaderLinkProps {
  url: string;
  text: string;
  className?: string;
}

/**
 * TODO: Matomo integration
 */
export function Layout() {
  const [isSidebarClosed, switchSidebar] = useState<boolean>(true);

  useEffect(() => {
    document.body.firstElementChild!.classList.remove("transition-preload");

    const sidebarState = getLocalStorageItem("sidebar_state");

    killAnimations();
    switchSidebar(sidebarState === "true");

    window.addEventListener("resize", onResize);

    return () => {
      window.removeEventListener("resize", onResize);
    };
  }, []);

  function closeSidebar(_?: unknown, setState = true) {
    if (setState && window.innerWidth > 1020) {
      setLocalStorageItem("sidebar_state", !isSidebarClosed ? "true" : "false");
    }

    switchSidebar((isClosed) => !isClosed);
  }

  function onResize() {
    const sidebarState = getLocalStorageItem("sidebar_state");

    if (typeof sidebarState !== "string") {
      return;
    }

    const isTrue = sidebarState === "true";

    if (window.innerWidth <= 1020) {
      if (isTrue && isSidebarClosed) {
        killAnimations();
        closeSidebar(null, false);
      }
    } else if (isTrue && !isSidebarClosed) {
      killAnimations();
      closeSidebar();
    }
  }

  function killAnimations() {
    document.body.firstElementChild!.classList.add("transition-preload");
    requestAnimationFrame(() =>
      setInterval(() =>
        document.body.firstElementChild!.classList.remove("transition-preload")
      )
    );
  }

  return (
    <ClientProvider>
      <HelmetProvider>
        <GlobalSidebar
          isSidebarClosed={isSidebarClosed}
          closeSidebar={closeSidebar}
        />

        <GlobalBody
          isSidebarClosed={isSidebarClosed}
          closeSidebar={closeSidebar}
        >
          <Outlet />
        </GlobalBody>

        <ScrollRestoration />
      </HelmetProvider>
    </ClientProvider>
  );
}

function GlobalSidebar({ isSidebarClosed, closeSidebar }: IGlobalSidebarProps) {
  const navListItems: INavItem[][] = [
    [
      {
        header: true,
        text: ARTISTS_OR_CREATORS,
        icon: "/static/menu/artists.svg",
      },
      {
        text: "Search",
        link: "/artists",
        icon: "/static/menu/search.svg",
      },
      {
        text: "Recent",
        link: "/artists/updated",
        icon: "/static/menu/recent.svg",
      },
      {
        text: "Random",
        link: "/artists/random",
        icon: "/static/menu/random1.svg",
      },
    ],
    [
      { header: true, text: "Posts", icon: "/static/menu/posts.svg" },
      { text: "Search", link: "/posts", icon: "/static/menu/search.svg" },
      {
        text: "DMs",
        link: "/dms",
        icon: "/static/menu/dm.svg",
        disable: DISABLE_DMS,
      },
      {
        text: "Popular",
        link: "/posts/popular",
        icon: "/static/menu/recent.svg",
      },
      {
        text: "Hash Lookup",
        link: "/search_hash",
        icon: "/static/menu/search.svg",
      },
      { text: "Tags", link: "/posts/tags", icon: "/static/menu/tag.svg" },
      {
        text: "Random",
        link: "/posts/random",
        icon: "/static/menu/random2.svg",
      },
    ],
    [
      { header: true, text: "Importer", icon: "/static/menu/importer.svg" },
      { text: "Import", link: "/importer", icon: "/static/menu/import.svg" },
      {
        text: "FAQ",
        link: "/importer/tutorial",
        icon: "/static/menu/faq.svg",
        disable: DISABLE_FAQ,
      },
    ],
    // [
    //   { header: true, text: "Documentation" },
    //   {
    //     text: "API",
    //     link: String(createAPIDocumentationPageURL()),
    //   },
    // ],
    [
      { header: true, text: "Filehaus", disable: DISABLE_FILEHAUS },
      { text: "Recent", link: "/shares", disable: DISABLE_FILEHAUS },
    ],
  ];

  const globalSidebarClassName = clsx(
    "global-sidebar",
    isSidebarClosed ? "retracted" : "expanded"
  );

  return (
    <div className={globalSidebarClassName}>
      <NavEntry className="clickable-header-entry">
        <NavItem
          link="/"
          text="Home"
          className="clickable-header home-button"
          icon="/static/menu/home.svg"
        />

        <div className="close-sidebar" onClick={closeSidebar}>
          <img src="/static/close.svg" />
        </div>
      </NavEntry>

      <NavList items={navListItems} />

      <AccountEntry />

      <NavEntry items={SIDEBAR_ITEMS} className="stuck-bottom" />
    </div>
  );
}

/**
 * TODO: a better auth state tracking
 */
function AccountEntry() {
  const location = useLocation();
  const [isLoggedIn, switchLoggedIn] = useState(false);
  const [isLoading, switchLoading] = useState<boolean>(true);
  const [isPendingDMsForReview, switchPendingDMsForReview] = useState(false);

  useEffect(() => {
    (async () => {
      const isRegistered = await isRegisteredAccount();

      if (!isRegistered) {
        return;
      }

      const isPending = await fetchHasPendingDMs();
      switchPendingDMsForReview(isPending);
    })();
  }, []);

  useEffect(() => {
    (async () => {
      try {
        switchLoading(true);

        const isRegistered = await isRegisteredAccount();
        switchLoggedIn(isRegistered);
      } finally {
        switchLoading(false);
      }
    })();
  }, [location]);

  const loggedOutEntries: INavItem[] = [
    {
      header: true,
      text: "Account",
      className: "account-header",
      icon: "/static/menu/account.svg",
    },
    {
      text: "Register",
      link: String(createRegistrationPageURL(location.pathname)),
      className: "register",
      icon: "/static/menu/register.svg",
    },
    {
      text: "Login",
      link: String(createLoginPageURL(location.pathname)),
      className: "login",
      icon: "/static/menu/login.svg",
    },
  ];
  const loggedInEntries: INavItem[] = [
    {
      header: true,
      text: "Account",
      link: "/account",
      className: "account-header",
      icon: "/static/menu/account.svg",
    },
    {
      text: "Keys",
      link: `/account/keys`,
      icon: "/static/menu/keys.svg",
    },
    {
      text: "Favorites",
      link: String(createAccountFavoriteProfilesPageURL()),
      className: "favorites",
      icon: "/static/menu/favorites.svg",
    },
    {
      text: "Review DMs",
      link: "/account/review_dms",
      className: "review_dms",
      icon: isPendingDMsForReview
        ? "/static/menu/red_dm.svg"
        : "/static/menu/dm.svg",
    },
    {
      text: "Logout",
      link: String(createLogoutPageURL()),
      className: "logout",
      icon: "/static/menu/logout.svg",
    },
  ];

  return isLoading ? (
    <LoadingIcon />
  ) : (
    <NavEntry
      items={isLoggedIn ? loggedInEntries : loggedOutEntries}
      className="account"
    />
  );
}

function GlobalBody({
  isSidebarClosed,
  closeSidebar,
  children,
}: IGlobalBodyProps) {
  const location = useLocation();
  const [isLoggedIn, switchLoggedIn] = useState(false);
  const [isLoading, switchLoading] = useState<boolean>(true);
  const contentWrapperClassName = clsx(
    "content-wrapper",
    !isSidebarClosed && "shifted"
  );
  const backdropClassName = clsx(
    "backdrop",
    isSidebarClosed && "backdrop-hidden"
  );
  const headerClassName = clsx(
    "header",
    isSidebarClosed && "sidebar-retracted"
  );

  useEffect(() => {
    (async () => {
      try {
        switchLoading(true);

        const isRegistered = await isRegisteredAccount();
        switchLoggedIn(isRegistered);
      } finally {
        switchLoading(false);
      }
    })();
  }, [location]);

  return (
    <div className={contentWrapperClassName}>
      <div className={backdropClassName} onClick={closeSidebar} />

      <div className={headerClassName}>
        <div id="burgor" onClick={closeSidebar}>
          <img src="/static/menu.svg" />
        </div>
        <HeaderLink url="/" text="Home" className="home" />
        <HeaderLink url="/artists" text={ARTISTS_OR_CREATORS} />
        <HeaderLink url="/posts" text="Posts" />
        <HeaderLink url="/importer" text="Import" className="import" />
        {isLoading ? (
          <LoadingIcon />
        ) : isLoggedIn ? (
          <>
            <HeaderLink
              url={String(createAccountFavoriteProfilesPageURL())}
              text="Favorites"
            />
            <HeaderLink url={String(createLogoutPageURL())} text="Logout" />
          </>
        ) : (
          <>
            <HeaderLink
              url={String(createRegistrationPageURL(location.pathname))}
              text="Register"
              className="register"
            />
            <HeaderLink
              url={String(createLoginPageURL(location.pathname))}
              text="Login"
              className="login"
            />
          </>
        )}
      </div>

      {BANNER_GLOBAL && (
        <aside dangerouslySetInnerHTML={{ __html: atob(BANNER_GLOBAL) }} />
      )}

      <main className="main" id="main">
        {children}
      </main>

      <GlobalFooter />

    </div>
  );
}

function HeaderLink({ url, text, className }: IHeaderLinkProps) {
  return (
    <Link to={url} className={clsx("header-link", className)}>
      {text}
    </Link>
  );
}
