import { Button, FormControlLabel, Grid, Switch, Typography } from "@material-ui/core";
import SendIcon from "@material-ui/icons/Send";
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, SELECT_VERSION, 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 { DropDownList } from "../../Controls/DropDownList";
import FleetSelectionTable from "../../Controls/FleetSelectionTable";
import { RoleWrap } from "../../Controls/RoleWrap";
import SearchField from "../../Controls/SearchField";
import useStyles from "../../useStyles";

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, updateSUMSVersion} = useCarUpdatesContext();
  const {
    groups,
    providers,
    token: {
      idToken: {jwtToken: token},
    },
  } = useUserContext();
  const {setMessage, setTitle, setSitePath} = useStatusContext();
  const [manifestName, setManifestName] = useState("");
  const [version, setVersion] = useState("");
  const [sumsVersion, setSUMSersion] = useState("");
  const [createDate, setCreateDate] = useState("");
  const [selected, setSelected] = useState([]);
  const [search, setSearch] = useState("");
  const [softwareVersion, setSoftwareVersion] = useState(SELECT_VERSION);
  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 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 (event) => {
    try {
      event.preventDefault();
      const data = {
        manifest_id: parseInt(manifest_id),
      }
      if (sumsVersion.length === 0) {
        await updateSUMSVersion(manifest_id, softwareVersion, token);
      }

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

  const getData = async () => {
    try {
      await getManifests({id: parseInt(manifest_id)}, token);
      await getSUMSVersions(token);
    } catch (e) {
      setMessage(e.message);
      logger.warn(e.stack);
    }
  };

  const changeVersion = (e) => {
    setSoftwareVersion(e.target.value);
  }

  useEffect(() => {
    getData();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [token]);

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

  useEffect(() => {
    if (!manifests || manifests.length === 0) return;
    const data = manifests[0];

    setManifestName(data.name);
    setVersion(data.version);
    setSUMSersion(data.sums || "");
    setCreateDate(LocalDateTimeString(data.created));
  }, [manifests]);

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

  return (
    <div className={classes.paper}>
      <form className={classes.form} noValidate action="{onSubmit}">
        <Typography variant="body2">Created {createDate}.</Typography>
        <Grid container className={classes.root} spacing={2}>
          <Grid item md={2}>
            <div
              className={classes.labelInline}
            >{`${selected.length} Selected`}</div>
          </Grid>
          <Grid item md={2} className={classes.textCenterAlign}>
            <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 md={4} className={classes.textCenterAlign}>
            <SearchField classes={classes} onSearch={handleSearch}/>
          </Grid>
          <Grid item md={4} container justifyContent="flex-end">
            {sumsVersion.length === 0 &&
              <DropDownList
                label="Software Version"
                labelField="version"
                valueField="version"
                value={softwareVersion}
                data={versions}
                classes={classes}
                onChange={changeVersion} />
          }
            <Button
              type="submit"
              disabled={busy || selected.length === 0 || (sumsVersion.length === 0 && softwareVersion === SELECT_VERSION)}
              color="primary"
              onClick={onSubmit}
            >
                <SendIcon />
            </Button>
          </Grid>
        </Grid>
        {updateType === CAR_UPDATE ?
          <VehicleProvider>
            <CarSelectionTable
              classes={classes}
              token={token}
              multiSelect={true}
              search={{search}}
              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;