// @flow
import { observable } from "mobx";
import { observer, inject } from "mobx-react";
import { MenuIcon } from "outline-icons";
import * as React from "react";
import { Helmet } from "react-helmet";
import { withTranslation, type TFunction } from "react-i18next";
import keydown from "react-keydown";
import { Switch, Route, Redirect } from "react-router-dom";
import styled, { withTheme } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import AuthStore from "stores/AuthStore";
import DocumentsStore from "stores/DocumentsStore";
import UiStore from "stores/UiStore";
import ErrorSuspended from "scenes/ErrorSuspended";
import KeyboardShortcuts from "scenes/KeyboardShortcuts";
import Analytics from "components/Analytics";
import Button from "components/Button";
import DocumentHistory from "components/DocumentHistory";
import Flex from "components/Flex";
import { LoadingIndicatorBar } from "components/LoadingIndicator";
import Modal from "components/Modal";
import Sidebar from "components/Sidebar";
import SettingsSidebar from "components/Sidebar/Settings";
import SkipNavContent from "components/SkipNavContent";
import SkipNavLink from "components/SkipNavLink";
import { type Theme } from "types";
import { meta } from "utils/keyboard";
import {
  homeUrl,
  searchUrl,
  matchDocumentSlug as slug,
} from "utils/routeHelpers";

type Props = {
  documents: DocumentsStore,
  children?: ?React.Node,
  actions?: ?React.Node,
  title?: ?React.Node,
  auth: AuthStore,
  ui: UiStore,
  notifications?: React.Node,
  theme: Theme,
  i18n: Object,
  t: TFunction,
};

@observer
class Layout extends React.Component<Props> {
  scrollable: ?HTMLDivElement;
  @observable redirectTo: ?string;
  @observable keyboardShortcutsOpen: boolean = false;

  constructor(props: Props) {
    super();
    this.updateBackground(props);
  }

  componentDidUpdate() {
    this.updateBackground(this.props);

    if (this.redirectTo) {
      this.redirectTo = undefined;
    }
  }

  updateBackground(props: Props) {
    // ensure the wider page color always matches the theme
    window.document.body.style.background = props.theme.background;
  }

  @keydown(`${meta}+.`)
  handleToggleSidebar() {
    this.props.ui.toggleCollapsedSidebar();
  }

  @keydown("shift+/")
  handleOpenKeyboardShortcuts() {
    if (this.props.ui.editMode) return;
    this.keyboardShortcutsOpen = true;
  }

  handleCloseKeyboardShortcuts = () => {
    this.keyboardShortcutsOpen = false;
  };

  @keydown(["t", "/", `${meta}+k`])
  goToSearch(ev: SyntheticEvent<>) {
    if (this.props.ui.editMode) return;
    ev.preventDefault();
    ev.stopPropagation();
    this.redirectTo = searchUrl();
  }

  @keydown("d")
  goToDashboard() {
    if (this.props.ui.editMode) return;
    this.redirectTo = homeUrl();
  }

  render() {
    const { auth, t, ui } = this.props;
    const { user, team } = auth;
    const showSidebar = auth.authenticated && user && team;
    const sidebarCollapsed = ui.editMode || ui.sidebarCollapsed;

    if (auth.isSuspended) return <ErrorSuspended />;
    if (this.redirectTo) return <Redirect to={this.redirectTo} push />;

    return (
      <Container column auto>
        <Helmet>
          <title>{team && team.name ? team.name : "Outline"}</title>
          <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0"
          />
        </Helmet>
        <SkipNavLink />
        <Analytics />

        {this.props.ui.progressBarVisible && <LoadingIndicatorBar />}
        {this.props.notifications}

        <MobileMenuButton
          onClick={ui.toggleMobileSidebar}
          icon={<MenuIcon />}
          iconColor="currentColor"
          neutral
        />

        <Container auto>
          {showSidebar && (
            <Switch>
              <Route path="/settings" component={SettingsSidebar} />
              <Route component={Sidebar} />
            </Switch>
          )}

          <SkipNavContent />
          <Content
            auto
            justify="center"
            $isResizing={ui.sidebarIsResizing}
            $sidebarCollapsed={sidebarCollapsed}
            style={
              sidebarCollapsed
                ? undefined
                : { marginLeft: `${ui.sidebarWidth}px` }
            }
          >
            {this.props.children}
          </Content>

          <Switch>
            <Route
              path={`/doc/${slug}/history/:revisionId?`}
              component={DocumentHistory}
            />
          </Switch>
        </Container>
        <Modal
          isOpen={this.keyboardShortcutsOpen}
          onRequestClose={this.handleCloseKeyboardShortcuts}
          title={t("Keyboard shortcuts")}
        >
          <KeyboardShortcuts />
        </Modal>
      </Container>
    );
  }
}

const Container = styled(Flex)`
  background: ${(props) => props.theme.background};
  transition: ${(props) => props.theme.backgroundTransition};
  position: relative;
  width: 100%;
  min-height: 100%;
`;

const MobileMenuButton = styled(Button)`
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: ${(props) => props.theme.depths.sidebar - 1};

  ${breakpoint("tablet")`
    display: none;
  `};
`;

const Content = styled(Flex)`
  margin: 0;
  transition: ${(props) =>
    props.$isResizing ? "none" : `margin-left 100ms ease-out`};

  @media print {
    margin: 0;
  }

  ${breakpoint("mobile", "tablet")`
    margin-left: 0 !important;
  `}

  ${breakpoint("tablet")`
    ${(props) =>
      props.$sidebarCollapsed &&
      `margin-left: ${props.theme.sidebarCollapsedWidth}px;`}
  `};
`;

export default withTranslation()<Layout>(
  inject("auth", "ui", "documents")(withTheme(Layout))
);
