import { Button } from "@mui/material";
import Box from "@mui/material/Box";
import { useTheme } from "@mui/material/styles";
import Toolbar from "@mui/material/Toolbar";
import useMediaQuery from "@mui/material/useMediaQuery";
import * as React from "react";
import { Outlet, useNavigate } from "react-router";
import { AuthApi, type UserInfo } from "../../api/AuthApi";
import { useAuth } from "../../App";
import { useAlert } from "../../hooks/contexts_provider/AlertDialogProvider";
import { useLoadingMessage } from "../../hooks/contexts_provider/LoadingMessageProvider";
import { AsyncWidget } from "../AsyncWidget";
import DashboardHeader from "./DashboardHeader";
import DashboardSidebar from "./DashboardSidebar";

interface UserInfoContext {
  info: UserInfo;
  reloadUserInfo: () => void;
  signOut: () => void;
}

const UserInfoContextK = React.createContext<UserInfoContext | null>(null);

export default function BaseAuthenticatedPage(): React.ReactElement {
  const theme = useTheme();
  const alert = useAlert();
  const loadingMessage = useLoadingMessage();

  const [userInfo, setuserInfo] = React.useState<null | UserInfo>(null);
  const loadUserInfo = async () => {
    setuserInfo(await AuthApi.GetUserInfo());
  };

  const reloadUserInfo = async () => {
    try {
      loadingMessage.show("Refreshing user information...");
      await loadUserInfo();
    } catch (e) {
      console.error(`Failed to load user information! ${e}`);
      alert(`Failed to load user information! ${e}`);
    } finally {
      loadingMessage.hide();
    }
  };

  const auth = useAuth();
  const navigate = useNavigate();

  const signOut = () => {
    AuthApi.SignOut();
    navigate("/");
    auth.setSignedIn(false);
  };

  const [isDesktopNavigationExpanded, setIsDesktopNavigationExpanded] =
    React.useState(false);
  const [isMobileNavigationExpanded, setIsMobileNavigationExpanded] =
    React.useState(false);

  const isOverMdViewport = useMediaQuery(theme.breakpoints.up("md"));

  const isNavigationExpanded = isOverMdViewport
    ? isDesktopNavigationExpanded
    : isMobileNavigationExpanded;

  const setIsNavigationExpanded = React.useCallback(
    (newExpanded: boolean) => {
      if (isOverMdViewport) {
        setIsDesktopNavigationExpanded(newExpanded);
      } else {
        setIsMobileNavigationExpanded(newExpanded);
      }
    },
    [
      isOverMdViewport,
      setIsDesktopNavigationExpanded,
      setIsMobileNavigationExpanded,
    ]
  );

  const handleToggleHeaderMenu = React.useCallback(
    (isExpanded: boolean) => {
      setIsNavigationExpanded(isExpanded);
    },
    [setIsNavigationExpanded]
  );

  const layoutRef = React.useRef<HTMLDivElement>(null);

  return (
    <AsyncWidget
      loadKey="1"
      load={loadUserInfo}
      errMsg="Failed to load user information!"
      errAdditionalElement={() => (
        <>
          <Button onClick={signOut}>Sign out</Button>
        </>
      )}
      build={() => (
        <UserInfoContextK
          value={{
            info: userInfo!,
            reloadUserInfo,
            signOut,
          }}
        >
          <Box
            ref={layoutRef}
            sx={{
              position: "relative",
              display: "flex",
              overflow: "hidden",
              height: "100%",
              width: "100%",
            }}
          >
            <DashboardHeader
              menuOpen={isNavigationExpanded}
              onToggleMenu={handleToggleHeaderMenu}
            />
            <DashboardSidebar
              expanded={isNavigationExpanded}
              setExpanded={setIsNavigationExpanded}
              container={layoutRef?.current ?? undefined}
            />
            <Box
              sx={{
                display: "flex",
                flexDirection: "column",
                flex: 1,
                minWidth: 0,
              }}
            >
              <Toolbar sx={{ displayPrint: "none" }} />
              <Box
                component="main"
                sx={{
                  display: "flex",
                  flexDirection: "column",
                  flex: 1,
                  overflow: "auto",
                }}
              >
                <Outlet />
              </Box>
            </Box>
          </Box>
        </UserInfoContextK>
      )}
    />
  );
}

export function useUserInfo(): UserInfoContext {
  return React.use(UserInfoContextK)!;
}
