import { useEffect, useState } from "react";
import {
  Box,
  Checkbox,
  FormControl,
  FormControlLabel,
  IconButton,
  Input,
  InputLabel,
  FormHelperText,
  Modal,
  TextField,
  Typography,
  Button,
} from "@material-ui/core";
import CloseIcon from '@mui/icons-material/Close';
import SendIcon from "@material-ui/icons/Send";

import { SELECT_VERSION } from "../../Contexts/CarUpdatesContext";
import { useManifestsContext } from "../../Contexts/ManifestsContext";
import { useStatusContext } from "../../Contexts/StatusContext";
import { useUserContext } from "../../Contexts/UserContext";

import { DropDownList } from "../../Controls/DropDownList";

const style = {
  position: 'absolute',
  top: '50%',
  left: '50%',
  transform: 'translate(-50%, -50%)',
  width: 400,
  bgcolor: 'background.paper',
  boxShadow: 24,
  borderRadius: 8,
  p: 4,
};

/**
 * Checks several required fields
 * @param {Manifest} manifest 
 * @returns []bool representing each valid field
 */
const validateManifestFields = (manifest = {}) => [
  manifest.sums && manifest.sums !== SELECT_VERSION,
  manifest.max_attempts > 0,
  manifest.update_duration > 0,
];

/**
 * Returns true if manifests have different values
 * @param {Manifest} a
 * @param {Manifest} b
 * @returns bool
 */
const diffManifestFields = (a = {}, b = {}) => (
  a.release_notes !== b.release_notes ||
  a.max_attempts !== b.max_attempts ||
  a.update_duration !== b.update_duration ||
  a.sums !== b.sums
);

export default function Configure({
  manifest = {},
  classes,
  versions = [SELECT_VERSION],
  disabled = true,
  submit = () => { },
}) {
  const { updateManifest } = useManifestsContext();
  const {
    token: {
      idToken: { jwtToken: token },
    },
  } = useUserContext();
  const { setMessage } = useStatusContext();

  const [open, setOpen] = useState(false);
  const [localManifest, setLocalManifest] = useState(structuredClone(manifest));

  const [satisfiesRequiredFields, setSatisfiesRequiredFields] = useState(validateManifestFields(localManifest));
  const needsConfiguration = satisfiesRequiredFields.some(valid => !valid);

  const handleOpen = () => {
    if (needsConfiguration) {
      setOpen(true);
    } else {
      onSubmit(); // skip openning modal, if fully configured
    }
  }
  const handleClose = () => setOpen(false);

  const handleManifestField = (field, value) => {
    if (!field || !value) {
      return;
    }
    setLocalManifest((manifest) => {
      manifest[field] = value;
      return structuredClone(manifest);
    });
  }

  const onSubmit = async () => {
    handleClose();
    if (diffManifestFields(manifest, localManifest)) {
      try {
        localManifest.update_duration = parseInt(localManifest.update_duration);
        localManifest.max_attempts = parseInt(localManifest.max_attempts);

        const result = await updateManifest(manifest.id, localManifest, token);

        if (!result || result.error) {
          return;
        }

        setMessage(`Updated manifest ${manifest.id}`);
      } catch (err) {
        setMessage(`Failed to update manifest ${manifest.id}`);
      }
    }
    submit();
  }

  useEffect(() => {
    setSatisfiesRequiredFields(validateManifestFields(localManifest));
  }, [localManifest, setSatisfiesRequiredFields])

  return (
    <>
      <IconButton onClick={handleOpen} disabled={disabled}>
        <SendIcon />
      </IconButton>
      <Modal
        open={open}
        onClose={handleClose}
        aria-labelledby="modal-modal-title"
        aria-describedby="modal-modal-description"
      >
        <Box sx={style}>
          <IconButton
            color="action"
            onClick={handleClose}
            edge={false}
            className={classes.closeModal}
          >
            <CloseIcon />
          </IconButton>
          <Typography id="modal-modal-title" variant="h6" component="h2">
            Complete Manifest
          </Typography>
          <Typography id="modal-modal-description">
            {manifest.name ? (<i>{manifest.name}</i>) : `This manifest`} is incomplete, and cannot be deployed without all required fields filled out.
          </Typography>
          <br />
          <FormControlLabel control={
            <Checkbox
              checked={localManifest.notify_sap}
              onChange={(e) => handleManifestField("notify_sap", e.target.checked)}
            />
          } label="Notify SAP for OTA Campaign" />
          <DropDownList
            label="Sums Version"
            labelField="version"
            valueField="version"
            value={localManifest.sums}
            data={versions}
            classes={classes}
            onChange={(e) => handleManifestField("sums", e.target.value)}
            error={!satisfiesRequiredFields[0]}
            fullWidth
          />
          <ConfigureInput
            name="Max Attempts"
            description="How many times should the car try and install the mainfest?"
            value={localManifest.max_attempts}
            setValue={(value) => handleManifestField("max_attempts", value)}
            error={!satisfiesRequiredFields[1]}
          />
          <ConfigureInput
            name="Update Duration"
            description="How long should the car try installing the manifest for?"
            value={localManifest.update_duration}
            setValue={(value) => handleManifestField("update_duration", value)}
            error={!satisfiesRequiredFields[2]}
          />
          <TextField
            label="Release Notes"
            value={localManifest.release_notes}
            onChange={(value) => handleManifestField("release_notes", value)}
            fullWidth
          />
          <Button
            variant="contained"
            className={classes.marginTop}
            disabled={needsConfiguration}
            onClick={onSubmit}
          >
            Update and Send
          </Button>
        </Box>
      </Modal>
    </>
  );
}

function kebab(str) {
  return str.replaceAll(" ", "-").toLowerCase();
}

function ConfigureInput({
  name,
  description,
  value = 0,
  setValue = () => { },
  error,
}) {
  const inputId = `deploy-configure-${kebab(name)}`;
  const descriptionId = `deploy-configure-${kebab(name)}-explain`;

  const handleChange = (event) => {
    setValue(event.target.value);
  }
  return (
    <Box sx={{ my: 2 }}>
      <FormControl fullWidth>
        <InputLabel htmlFor={inputId}>{name}</InputLabel>
        <Input
          id={inputId}
          aria-describedby={descriptionId}
          type="number"
          value={value}
          onChange={handleChange}
          error={error}
        />
        <FormHelperText id={descriptionId}>{description}</FormHelperText>
      </FormControl>
    </Box>
  );
}
