import { Checkbox, FormControlLabel, Grid, MenuItem, Switch, Typography, Box } from "@material-ui/core";
import React, { useEffect, useState } from "react";
import { Redirect, useParams } from "react-router";

import { logger } from "../../../services/monitoring";
import { LocalDateTimeString } from "../../../utils/dates";
import { Permissions } from "../../../utils/roles";
import { CarUpdatesProvider, useCarUpdatesContext } from "../../Contexts/CarUpdatesContext";
import { FleetProvider } from "../../Contexts/FleetContext";
import { ManifestsProvider, useManifestsContext } from "../../Contexts/ManifestsContext";
import { useStatusContext } from "../../Contexts/StatusContext";
import { useUserContext } from "../../Contexts/UserContext";
import { VehicleProvider } from "../../Contexts/VehicleContext";
import CarSelectionTable from "../../Controls/CarSelectionTable";
import OptionsDropdown from "../../Controls/OptionsDropdown";
import FleetSelectionTable from "../../Controls/FleetSelectionTable";
import { RoleWrap } from "../../Controls/RoleWrap";
import SearchField from "../../Controls/SearchField";
import useStyles from "../../useStyles";
import Configure from "./Configure";

const CAR_UPDATE = false;
const FLEET_UPDATE = true;

const MainForm = () => {
  const [updateType, setUpdateType] = useState(CAR_UPDATE);
  const { manifest_id } = useParams();
  const { getManifests, manifests, busy } = useManifestsContext();
  const { deployCarUpdates, deployFleetUpdates, getSUMSVersions, versions } = useCarUpdatesContext();
  const {
    groups,
    providers,
    token: {
      idToken: { jwtToken: token },
    },
  } = useUserContext();
  const { setMessage, setTitle, setSitePath } = useStatusContext();
  const [manifest, setManifest] = useState({});
  const [selected, setSelected] = useState([]);
  const [search, setSearch] = useState("");
  const [online, setOnline] = useState(false);
  const [onlineHMI, setOnlineHMI] = useState(false);
  const [redirect, setRedirect] = useState("");
  const classes = useStyles();

  const handleChange = (_) => {
    setSelected([]);
    setUpdateType(updateType === CAR_UPDATE ? FLEET_UPDATE : CAR_UPDATE);
  }

  const handleSearch = (query) => {
    setSelected([]);
    setSearch(query);
  };

  const handleOnline = (event) => {
    setOnline(event.target.checked);
  };

  const handleOnlineHMI = (event) => {
    setOnlineHMI(event.target.checked);
  };

  const handleSelectAll = (cars) => {
    setSelected(cars);
  };

  const handleSelect = (event, key) => {
    try {
      let newSelected;
      if (event.target.checked) {
        newSelected = [...selected];
        newSelected.push(key);
      } else {
        newSelected = selected.filter((vinOrName) => vinOrName !== key);
      }
      setSelected(newSelected);
    } catch (e) {
      logger.warn(e.stack);
    }
  };

  const onSubmit = async () => {
    try {
      const data = {
        manifest_id: parseInt(manifest_id),
      }

      if (updateType === CAR_UPDATE) {
        data.vins = selected;
        await deployCarUpdates(data, token);
      } else {
        data.fleet_names = selected;
        await deployFleetUpdates(data, token);
      }
      setMessage(
        `Deployed ${manifest.name} ${manifest.version} to ${selected.length} cars`
      );
      setRedirect(`/package-status/${manifest_id}`);
    } catch (e) {
      setMessage(e.message);
      logger.warn(e.stack);
    }
  };

  useEffect(() => {
    const control = new AbortController();

    const fetchData = async () => {
      try {
        await getManifests({
          id: parseInt(manifest_id),
          signal: control.signal,
        }, token);
        await getSUMSVersions(token);
      } catch (e) {
        setMessage(e.message);
        logger.warn(e.stack);
      }
    }
    fetchData();
    return () => {
      control.abort();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [manifest_id, token]);

  useEffect(() => {
    if (manifests && manifests.length !== 0) {
      setManifest(manifests[0]);
    }
  }, [manifests]);

  useEffect(() => {
    if (manifest) {
      const title = `Deploy ${manifest.name} ${manifest.version}`;
      setTitle(title);
      setSitePath([
        {
          label: "Deployments",
          link: "/packages",
        },
        {
          label: title,
        },
      ]);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [manifest]);

  if (redirect.length > 0) {
    return <Redirect to={redirect} />;
  }

  if (!manifest && !manifest?.name) {
    return (
      <div>Loading...</div>
    );
  }

  return (
    <div className={classes.paper}>
      <form className={classes.form} noValidate>
        <Typography variant="body2">Created {LocalDateTimeString(manifest.created)}.</Typography>
        <Grid container
          className={classes.root}
          spacing={2}
          columns={{ xs: 4, sm: 6, md: 12 }}
        >
          <Grid item xs={2}>
            <div
              className={classes.labelInline}
            >{`${selected.length} Selected`}</div>
          </Grid>

          <Grid item xs={2}>
            <RoleWrap
              groups={groups}
              providers={providers}
              rolesPerProvider={Permissions.FiskerRead}
            >
              <FormControlLabel control={<Switch
                checked={updateType === CAR_UPDATE}
                onChange={handleChange}
                inputProps={{ 'aria-label': 'controlled' }}
              />} label="Car(default) or Fleet" />
            </RoleWrap>
          </Grid>

          <Grid item xs={4} sm={6}>
            <Box sx={{ display: "flex", width: "100%" }}>
              <SearchField classes={classes} onSearch={handleSearch} />
              <OptionsDropdown listId="filter-menu">
                <MenuItem>
                  <FormControlLabel
                    control={<Checkbox checked={online} onChange={handleOnline} />}
                    label="Only online"
                  />
                </MenuItem>
                <MenuItem>
                  <FormControlLabel
                    control={
                      <Checkbox checked={onlineHMI} onChange={handleOnlineHMI} />
                    }
                    label="Only online HMI"
                  />
                </MenuItem>
              </OptionsDropdown>
            </Box>
          </Grid>

          <Grid item xs="auto">
            <Configure
              manifest={manifest}
              classes={classes}
              versions={versions}
              disabled={busy || selected.length === 0}
              submit={onSubmit}
              key={manifest.name} // to trigger re-render of child on prop change
            />
          </Grid>
        </Grid>
        {updateType === CAR_UPDATE ?
          <VehicleProvider>
            <CarSelectionTable
              classes={classes}
              token={token}
              multiSelect={true}
              search={{
                search,
                online: online ? true : null,
                online_hmi: onlineHMI ? true : null,
              }}
              selected={selected}
              onSelect={handleSelect}
              onSelectAll={handleSelectAll}
            /></VehicleProvider> :
          <FleetProvider>
            <FleetSelectionTable
              classes={classes}
              token={token}
              multiSelect={true}
              search={{ search }}
              selected={selected}
              onSelect={handleSelect}
              onSelectAll={handleSelectAll} />
          </FleetProvider>
        }
      </form>
    </div>
  );
};

const ManifestDeployForm = () => (
  <ManifestsProvider>
    <CarUpdatesProvider>
      <MainForm />
    </CarUpdatesProvider>
  </ManifestsProvider>
);

export default ManifestDeployForm;