// This file is part of Moonfire NVR, a security camera network video recorder.
// Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception

import Container from "@material-ui/core/Container";
import React, { useEffect, useReducer, useState } from "react";
import * as api from "./api";
import MoonfireMenu from "./AppMenu";
import Login from "./Login";
import { useSnackbars } from "./snackbars";
import { Camera, Session } from "./types";
import ListActivity from "./List";
import AppBar from "@material-ui/core/AppBar";
import LiveActivity, { MultiviewChooser } from "./Live";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import ListIcon from "@material-ui/icons/List";
import Videocam from "@material-ui/icons/Videocam";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import FilterList from "@material-ui/icons/FilterList";
import IconButton from "@material-ui/core/IconButton";

export type LoginState =
  | "unknown"
  | "logged-in"
  | "not-logged-in"
  | "server-requires-login"
  | "user-requested-login";

type Activity = "list" | "live";

function App() {
  const [showMenu, toggleShowMenu] = useReducer((m: boolean) => !m, false);
  const [showListSelectors, toggleShowListSelectors] = useReducer(
    (m: boolean) => !m,
    true
  );
  const [activity, setActivity] = useState<Activity>("list");
  const [multiviewLayoutIndex, setMultiviewLayoutIndex] = useState(0);
  const [session, setSession] = useState<Session | null>(null);
  const [cameras, setCameras] = useState<Camera[] | null>(null);
  const [timeZoneName, setTimeZoneName] = useState<string | null>(null);
  const [fetchSeq, setFetchSeq] = useState(0);
  const [loginState, setLoginState] = useState<LoginState>("unknown");
  const [error, setError] = useState<api.FetchError | null>(null);
  const needNewFetch = () => setFetchSeq((seq) => seq + 1);
  const snackbars = useSnackbars();

  const clickActivity = (activity: Activity) => {
    toggleShowMenu();
    setActivity(activity);
  };

  const onLoginSuccess = () => {
    setLoginState("logged-in");
    needNewFetch();
  };

  const logout = async () => {
    const resp = await api.logout(
      {
        csrf: session!.csrf,
      },
      {}
    );
    switch (resp.status) {
      case "aborted":
        break;
      case "error":
        snackbars.enqueue({
          message: "Logout failed: " + resp.message,
        });
        break;
      case "success":
        setSession(null);
        needNewFetch();
        break;
    }
  };

  useEffect(() => {
    const abort = new AbortController();
    const doFetch = async (signal: AbortSignal) => {
      const resp = await api.toplevel({ signal });
      switch (resp.status) {
        case "aborted":
          break;
        case "error":
          if (resp.httpStatus === 401) {
            setLoginState("server-requires-login");
            return;
          }
          setError(resp);
          break;
        case "success":
          setError(null);
          setLoginState(
            resp.response.session === undefined ? "not-logged-in" : "logged-in"
          );
          setSession(resp.response.session || null);
          setCameras(resp.response.cameras);
          setTimeZoneName(resp.response.timeZoneName);
      }
    };
    doFetch(abort.signal);
    return () => {
      abort.abort();
    };
  }, [fetchSeq]);
  let activityMenu = null;
  let activityMain = null;
  if (error === null && cameras !== null && cameras.length > 0) {
    switch (activity) {
      case "list":
        activityMenu = (
          <IconButton
            aria-label="selectors"
            onClick={toggleShowListSelectors}
            color="inherit"
            size="small"
          >
            <FilterList />
          </IconButton>
        );
        activityMain = (
          <ListActivity
            cameras={cameras}
            showSelectors={showListSelectors}
            timeZoneName={timeZoneName!}
          />
        );
        break;
      case "live":
        activityMenu = (
          <MultiviewChooser
            layoutIndex={multiviewLayoutIndex}
            onChoice={setMultiviewLayoutIndex}
          />
        );
        activityMain = (
          <LiveActivity cameras={cameras} layoutIndex={multiviewLayoutIndex} />
        );
        break;
    }
  }
  return (
    <>
      <AppBar position="static">
        <MoonfireMenu
          loginState={loginState}
          setSession={setSession}
          requestLogin={() => {
            setLoginState("user-requested-login");
          }}
          logout={logout}
          menuClick={toggleShowMenu}
          activityMenuPart={activityMenu}
        />
      </AppBar>
      <Drawer
        variant="temporary"
        open={showMenu}
        onClose={toggleShowMenu}
        ModalProps={{
          keepMounted: true,
        }}
      >
        <List>
          <ListItem button key="list" onClick={() => clickActivity("list")}>
            <ListItemIcon>
              <ListIcon />
            </ListItemIcon>
            <ListItemText primary="List view" />
          </ListItem>
          <ListItem button key="live" onClick={() => clickActivity("live")}>
            <ListItemIcon>
              <Videocam />
            </ListItemIcon>
            <ListItemText primary="Live view (experimental)" />
          </ListItem>
        </List>
      </Drawer>
      <Login
        onSuccess={onLoginSuccess}
        open={
          loginState === "server-requires-login" ||
          loginState === "user-requested-login"
        }
        handleClose={() => {
          setLoginState((s) =>
            s === "user-requested-login" ? "not-logged-in" : s
          );
        }}
      />
      {error !== null && (
        <Container>
          <h2>Error querying server</h2>
          <pre>{error.message}</pre>
          <p>
            You may find more information in the Javascript console. Try
            reloading the page once you believe the problem is resolved.
          </p>
        </Container>
      )}
      {activityMain}
    </>
  );
}

export default App;
