import { AnimatePresence } from "framer-motion";
import { observer } from "mobx-react";
import * as React from "react";
import {
  Switch,
  Route,
  useLocation,
  matchPath,
  Redirect,
} from "react-router-dom";
import { TeamPreference } from "@shared/types";
import ErrorSuspended from "~/scenes/Errors/ErrorSuspended";
import Layout from "~/components/Layout";
import RegisterKeyDown from "~/components/RegisterKeyDown";
import Sidebar from "~/components/Sidebar";
import useCurrentTeam from "~/hooks/useCurrentTeam";
import { usePostLoginPath } from "~/hooks/useLastVisitedPath";
import usePolicy from "~/hooks/usePolicy";
import useStores from "~/hooks/useStores";
import history from "~/utils/history";
import lazyWithRetry from "~/utils/lazyWithRetry";
import {
  searchPath,
  newDocumentPath,
  settingsPath,
  matchDocumentHistory,
  matchDocumentSlug as slug,
} from "~/utils/routeHelpers";
import { DocumentContextProvider } from "./DocumentContext";
import Fade from "./Fade";
import { PortalContext } from "./Portal";
import CommandBar from "./CommandBar";

const DocumentComments = lazyWithRetry(
  () => import("~/scenes/Document/components/Comments/Comments")
);
const DocumentHistory = lazyWithRetry(
  () => import("~/scenes/Document/components/History")
);
const SettingsSidebar = lazyWithRetry(
  () => import("~/components/Sidebar/Settings")
);

type Props = {
  children?: React.ReactNode;
};

const AuthenticatedLayout: React.FC = ({ children }: Props) => {
  const { ui, auth } = useStores();
  const location = useLocation();
  const layoutRef = React.useRef<HTMLDivElement>(null);
  const can = usePolicy(ui.activeDocumentId);
  const canCollection = usePolicy(ui.activeCollectionId);
  const team = useCurrentTeam();
  const [spendPostLoginPath] = usePostLoginPath();

  const goToSearch = (ev: KeyboardEvent) => {
    if (!ev.metaKey && !ev.ctrlKey) {
      ev.preventDefault();
      ev.stopPropagation();
      history.push(searchPath());
    }
  };

  const goToNewDocument = (event: KeyboardEvent) => {
    if (event.metaKey || event.altKey) {
      return;
    }
    const { activeCollectionId } = ui;
    if (!activeCollectionId || !canCollection.createDocument) {
      return;
    }
    history.push(newDocumentPath(activeCollectionId));
  };

  if (auth.isSuspended) {
    return <ErrorSuspended />;
  }

  const postLoginPath = spendPostLoginPath();
  if (postLoginPath) {
    return <Redirect to={postLoginPath} />;
  }

  const sidebar = (
    <Fade>
      <Switch>
        <Route path={settingsPath()} component={SettingsSidebar} />
        <Route component={Sidebar} />
      </Switch>
    </Fade>
  );

  const showHistory =
    !!matchPath(location.pathname, {
      path: matchDocumentHistory,
    }) && can.listRevisions;
  const showComments =
    !showHistory &&
    can.comment &&
    ui.activeDocumentId &&
    ui.commentsExpanded &&
    !!team.getPreference(TeamPreference.Commenting);

  const sidebarRight = (
    <AnimatePresence
      initial={false}
      key={ui.activeDocumentId ? "active" : "inactive"}
    >
      {(showHistory || showComments) && (
        <Route path={`/doc/${slug}`}>
          <React.Suspense fallback={null}>
            {showHistory && <DocumentHistory />}
            {showComments && <DocumentComments />}
          </React.Suspense>
        </Route>
      )}
    </AnimatePresence>
  );

  return (
    <DocumentContextProvider>
      <PortalContext.Provider value={layoutRef.current}>
        <Layout
          title={team.name}
          sidebar={sidebar}
          sidebarRight={sidebarRight}
          ref={layoutRef}
        >
          <RegisterKeyDown trigger="n" handler={goToNewDocument} />
          <RegisterKeyDown trigger="t" handler={goToSearch} />
          <RegisterKeyDown trigger="/" handler={goToSearch} />
          {children}
          <CommandBar />
        </Layout>
      </PortalContext.Provider>
    </DocumentContextProvider>
  );
};

export default observer(AuthenticatedLayout);
