import { Button, Checkbox, DialogActions, DialogContent, DialogTitle, FormControl, FormControlLabel, FormHelperText, FormLabel, Grid2, IconButton, InputAdornment, List, ListItem, ListItemIcon, ListItemText, MenuItem, Select, Switch, TextField, Theme, Tooltip, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import classNames from "classnames";
import ResponsiveDialog from "common/ResponsiveDialog";
import { Option } from "common/SearchSelect";
import { capitalize, cloneDeep } from "lodash";
import { Component, Device, Interaction } from "models";
import { extension, getMeasurements } from "pbHelpers/ComponentType";
import { ComponentType, Measurement, Operator } from "pbHelpers/Enums";
import { describeMeasurement, MeasurementDescriber } from "pbHelpers/MeasurementDescriber";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import React from "react";
import { useEffect, useState } from "react";
import AddIcon from "@mui/icons-material/AddCircle";
import RemoveIcon from "@mui/icons-material/RemoveCircle";
import { green, red } from "@mui/material/colors";
import { or } from "utils";
import moment from "moment";
import { timeOfDayDescriptor } from "pbHelpers/Interaction";
import { TimePicker } from "@mui/x-date-pickers";
import { useInteractionsAPI, useSnackbar } from "hooks";
import { useGlobalState } from "providers";

interface Props {
  open: boolean
  onClose: (refreshCallback: boolean) => void
  linkedComponents: Map<string, Component>
  componentDevices: Map<string, number>
  //if we pass in a device id we could filter the components to only be for that device, this could be used for the control part
  device?: Device
}

const useStyles = makeStyles((theme: Theme) => {
  return (
    {
      borderedContainer: {
      padding: theme.spacing(1),
      marginBottom: theme.spacing(2),
      border: "1px solid rgba(255, 255, 255, 0.12)",
      borderRadius: "4px"
    },
    greenButton: {
      color: green["600"]
    },
    redButton: {
      color: red["600"]
    },
    noPadding: {
      padding: 0
    },
    forPrompt: {
      fontSize: "0.875em",
      marginTop: "10px"
    },
    timeRange: {
      fontSize: "0.875em",
      marginTop: "20px"
    },
    }
  )
})

export default function NewObjectInteraction(props: Props){
  const { open, onClose, device, linkedComponents, componentDevices } = props
  const classes = useStyles()
  const [{ as }] = useGlobalState();
  const {openSnack} = useSnackbar();
  const interactionsAPI = useInteractionsAPI();
  const [newAlertComponentType, setNewAlertComponentType] = useState<quack.ComponentType>(
    quack.ComponentType.COMPONENT_TYPE_INVALID
  );
  const [conditions, setConditions] = useState<pond.InteractionCondition[]>([]);
  const [selectedAlertComponents, setSelectedAlertComponents] = useState<string[]>([]);
  const [validOptions, setValidOptions] = useState<Option[]>([])
  const [validComponents, setValidComponents] = useState<Component[]>([])
    //condition value strings - so that decimals are easier to type into the field
  const [valStrings, setValStrings] = useState(["0", "0"]);
  const [numConditions, setNumConditions] = useState(0)
  const [nodeOptions, setNodeOptions] = useState<JSX.Element[]>([]);
  const [subtypeDropdown, setSubtypeDropdown] = useState<number>(0);
  const [nodeOne, setNodeOne] = useState(0)
  const [nodeTwo, setNodeTwo] = useState(0)
  const [maxConditions, setMaxConditions] = useState(2)
  const [resultType, setResultType] = useState<quack.InteractionResultType>(quack.InteractionResultType.INTERACTION_RESULT_TYPE_REPORT)
  const [sinkMotor, setSinkMotor] = useState(false)
  const [selectedSink, setSelectedSink] = useState("")//the key of the component to be the sink
  const [sinkOptions, setSinkOptions] = useState<Component[]>([])
  const [resultMode, setResultMode] = useState(0)
  const [resultValue, setResultValue] = useState("")
  const [dutyCycleEnabled, setDutyCycleEnabled] = useState(false)
  const [dutyCycle, setDutyCycle] = useState<string>("");
  const [reporting, setReporting] = useState(true)
  const [notify, setNotify] = useState(true)
  //schedule variables
  const [schedule, setSchedule] = useState(
    pond.InteractionSchedule.create({
      weekdays: ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
    })
  );
  
  

  useEffect(() => {
    //if the device is passed in need to filter out possible components
    let validCompList: Component[] = []
    let validOptions: Option[] = []
    let sinkOptions: Component[] = []

    if(device){
      setMaxConditions(device.maxConditions())
    }
    
    linkedComponents.forEach((comp, key) => {
      if(componentDevices.get(key) === device?.id() || !device){
        let ext = extension(comp.type(), comp.subType())
        if(ext.isController){
          sinkOptions.push(comp)
        }
        validCompList.push(comp)
      }
    })
    
    let included: quack.ComponentType[] = []
    validCompList.forEach(comp => {
      if(included.includes(comp.type())) return
      let ext = extension(comp.type(), comp.subType())
      if(device){
        if(!ext.isController){
          included.push(comp.type())
          validOptions.push({
            label: ext.friendlyName,
            value: comp.type()
          })
        }
      }else{
        included.push(comp.type())
        validOptions.push({
          label: ext.friendlyName,
          value: comp.type()
        })
      }

    })

    setValidOptions(validOptions)
    setValidComponents(validCompList)
    setSinkOptions(sinkOptions)
  },[device, linkedComponents, componentDevices])

  //use the selected components to determine the lowest amount of nodes for the options
  useEffect(() => {
    setNodeOne(0);
    setNodeTwo(0);
    setSubtypeDropdown(0);
    let nodeCount = 12; //start with the maximum number of nodes for a cable
    validComponents.forEach(comp => {
      if (selectedAlertComponents.includes(comp.key())) {
        if (comp.lastMeasurement[0] && comp.lastMeasurement[0].values[0]) {
          let nodes = comp.lastMeasurement[0].values[0].values.length;
          nodeCount = nodes < nodeCount ? nodes : nodeCount;
        }
      }
    });
    let options = [];
    for (let i = 0; i <= nodeCount; i++) {
      options.push(
        <MenuItem key={i} value={i}>
          {i === 0 ? "None" : "Node " + i}
        </MenuItem>
      );
    }
    setNodeOptions(options);
  }, [validComponents, selectedAlertComponents]);
  

  const close = (refresh: boolean) => {
    //reset the state variables to their default values
    setNewAlertComponentType(quack.ComponentType.COMPONENT_TYPE_INVALID);
    setConditions([]);
    setSelectedAlertComponents([]);
    setValidComponents([])
    setValStrings(["0", "0"]);
    setNumConditions(0)
    setNodeOptions([]);
    setSubtypeDropdown(0);
    setNodeOne(0)
    setNodeTwo(0)
    setMaxConditions(2)
    setResultType(quack.InteractionResultType.INTERACTION_RESULT_TYPE_REPORT)
    setSinkMotor(false)
    setSelectedSink("")//the key of the component to be the sink
    setSinkOptions([])
    setResultMode(0)
    setResultValue("")
    setDutyCycleEnabled(false)
    setDutyCycle("");
    setReporting(true)
    setNotify(true)
    onClose(refresh)
  }
  const availableMeasurementTypes = (type: quack.ComponentType): quack.MeasurementType[] => {
    return getMeasurements(type).map(m => m.measurementType);
  };
  
  const initialConditions = (type: quack.ComponentType): pond.InteractionCondition[] => {
    let measurementType = availableMeasurementTypes(type)[0];
    let condition = pond.InteractionCondition.create({
      measurementType: measurementType,
      comparison: measurementType === Measurement.boolean ? Operator.equals : Operator.less,
      value: 0
    });
    return [condition];
  };

  //display the components that match the type that was selected for the new alert
  const listMatchingComponents = () => {
    let matching: Component[] = [];
    validComponents.forEach(comp => {
      if (comp.type() === newAlertComponentType) {
        matching.push(comp);
      }
    });
    return (
      <List>
        {matching.map(comp => (
          <ListItem key={comp.key()}>
            <ListItemIcon>
              <Checkbox
                checked={selectedAlertComponents.includes(comp.key())}
                onChange={(_, checked) => {
                  let selected = selectedAlertComponents;
                  if (checked) {
                    selected.push(comp.key());
                  } else {
                    selected.splice(selected.indexOf(comp.key()), 1);
                  }
                  setSelectedAlertComponents([...selected]);
                }}
              />
            </ListItemIcon>
            <ListItemText>{comp.name()}</ListItemText>
          </ListItem>
        ))}
      </List>
    );
  };

  const measurementTypeMenuItems = () => {
    return availableMeasurementTypes(newAlertComponentType).map(measurementType => (
      <MenuItem key={measurementType} value={measurementType}>
        {describeMeasurement(measurementType).label()}
      </MenuItem>
    ));
  };

  const changeCondition = (newCondition: pond.InteractionCondition, index: number) => {
    let c = conditions;
    c[index] = newCondition;
    setConditions([...c]);
  };

  const conditionGroup = (condition: pond.InteractionCondition, index: number) => {
    let measurementType = condition.measurementType;
    let describer = describeMeasurement(measurementType, newAlertComponentType);
    let isBoolean = condition.measurementType === Measurement.boolean;
    return (
      <React.Fragment key={index}>
        <Grid2
          key={"interaction"}
          container
          direction="row"
          alignItems="center"
          spacing={2}>
          {index > 0 && (
            <Grid2 size={12}>
              <Typography align="center">AND</Typography>
            </Grid2>
          )}
          <Grid2 size={{ xs:10, sm:4 }}>
            <TextField
              select
              id="measurementType"
              required={true}
              label=""
              helperText="Measurement"
              //error={!isMeasurementTypeValid(interaction.settings.conditions[index].measurementType)}
              //disabled={!isSourceValid(interaction.settings.source) || !canEdit}
              value={condition.measurementType}
              onChange={event => {
                condition.measurementType = +event.target.value;
                changeCondition(condition, index);
              }}
              autoFocus={false}
              margin="dense"
              variant="standard"
              fullWidth
              InputLabelProps={{ shrink: true }}>
              {measurementTypeMenuItems()}
            </TextField>
          </Grid2>
          <Grid2 size={{ xs:10, sm:3 }}>
            <TextField
              select
              id="comparison"
              required={true}
              label=""
              helperText="Comparator"
              //disabled={!isSourceValid(interaction.settings.source) || isBoolean || !canEdit}
              value={condition.comparison}
              onChange={event => {
                condition.comparison = +event.target.value;
                changeCondition(condition, index);
              }}
              autoFocus={false}
              margin="dense"
              variant="standard"
              fullWidth
              InputLabelProps={{ shrink: true }}>
              {!isBoolean && [
                <MenuItem key={2} value={Operator.less}>
                  {"is below"}
                </MenuItem>,
                <MenuItem key={3} value={Operator.greater}>
                  {"is above"}
                </MenuItem>
              ]}
              <MenuItem key={1} value={Operator.equals}>
                {"is exactly"}
              </MenuItem>
            </TextField>
          </Grid2>
          <Grid2 size={{xs:8, sm:4}}>
            <TextField
              select={isBoolean}
              id="value"
              required={true}
              type={"text"}
              label=""
              helperText="Value"
              error={isNaN(+valStrings[index])}
              value={valStrings[index]}
              onChange={event => {
                let strings = valStrings;
                strings[index] = event.target.value;
                setValStrings([...strings]);
                if (!isNaN(+valStrings[index])) {
                  condition.value = describer.toStored(+event.target.value);
                  changeCondition(condition, index);
                }
              }}
              autoFocus={false}
              margin="dense"
              variant="standard"
              fullWidth
              InputProps={{
                endAdornment: <InputAdornment position="end">{describer.unit()}</InputAdornment>
              }}
              InputLabelProps={{ shrink: true }}>
              {isBoolean && [
                <MenuItem key={0} value={0}>
                  {describer.enumerations()[0]}
                </MenuItem>,
                <MenuItem key={1} value={1}>
                  {describer.enumerations()[1]}
                </MenuItem>
              ]}
            </TextField>
          </Grid2>
          <Grid2 size={{xs:2, sm:1}}>
            <Tooltip title="Remove this condition">
              <IconButton
                color="default"
                disabled={numConditions === 1}
                aria-label="Remove condition"
                onClick={() => {
                  conditions.splice(index, 1)
                  setNumConditions(conditions.length)
                }}
                className={classNames(classes.redButton, classes.noPadding)}>
                <RemoveIcon />
              </IconButton>
            </Tooltip>
          </Grid2>
        </Grid2>
        {nodeOptions.length > 2 && (
          <Grid2
            key={"nodes"}
            container
            direction="row"
            alignItems="center"
            spacing={2}>
            <Grid2 size={{xs:10, sm:4}}>
              <TextField
                select
                id="subtype"
                label="Subtype"
                //disabled={!isSourceValid(interaction.settings.source) || !canEdit}
                value={subtypeDropdown}
                onChange={event => {
                  setSubtypeDropdown(+event.target.value);
                }}
                margin="dense"
                variant="standard"
                fullWidth
                InputLabelProps={{ shrink: true }}>
                <MenuItem key={0} value={0}>
                  Any
                </MenuItem>
                <MenuItem key={1} value={1}>
                  Average
                </MenuItem>
                <MenuItem key={2} value={2}>
                  Single Node
                </MenuItem>
                <MenuItem key={3} value={3}>
                  Node Diff
                </MenuItem>
                <MenuItem key={4} value={4}>
                  Up To
                </MenuItem>
              </TextField>
            </Grid2>
            <Grid2 size={{xs:10, sm:4}}>
              {(subtypeDropdown === 2 || subtypeDropdown === 3 || subtypeDropdown === 4) && (
                <TextField
                  select
                  id="interactionType"
                  label="Node 1"
                  //disabled={!isSourceValid(interaction.settings.source) || !canEdit}
                  value={nodeOne}
                  onChange={event => {
                    setNodeOne(+event.target.value);
                  }}
                  margin="dense"
                  variant="standard"
                  fullWidth
                  InputLabelProps={{ shrink: true }}>
                  {nodeOptions}
                </TextField>
              )}
            </Grid2>
            <Grid2 size={{xs:10, sm:4}}>
              {subtypeDropdown === 3 && (
                <TextField
                  select
                  id="interactionType"
                  label="Node 2"
                  //disabled={!isSourceValid(interaction.settings.source) || !canEdit}
                  value={nodeTwo}
                  onChange={event => {
                    setNodeTwo(+event.target.value);
                  }}
                  margin="dense"
                  variant="standard"
                  fullWidth
                  InputLabelProps={{ shrink: true }}>
                  {nodeOptions}
                </TextField>
              )}
            </Grid2>
          </Grid2>
        )}
      </React.Fragment>
    );
  };

  const conditionInput = () => {
    return (
      <FormControl
        component={"fieldset" as "div"}
        className={classes.borderedContainer}
        fullWidth
        disabled={selectedAlertComponents.length === 0}>
        <FormLabel component={"legend" as "caption"}>Conditions</FormLabel>
        {selectedAlertComponents.length > 0 ? (
          <React.Fragment>
            {conditions.map((condition, i) => conditionGroup(condition, i))}
          </React.Fragment>
        ) : (
          <FormHelperText>You must select a source before adding conditions</FormHelperText>
        )}
        <Tooltip title="Add another condition">
          <IconButton
            color="primary"
            disabled={numConditions >= maxConditions}
            aria-label="Add another condition"
            onClick={() => {
              let newConditions = conditions.concat(initialConditions(newAlertComponentType));
              setConditions(newConditions);
              setNumConditions(newConditions.length)
            }}
            className={classNames(classes.greenButton, classes.noPadding)}>
            <AddIcon />
          </IconButton>
        </Tooltip>
      </FormControl>
    );
  };

  const sinkSelector = () => {
    return (
      <TextField
        select
        id="sink"
        label=""
        value={selectedSink}
        onChange={(e) => {
          setSelectedSink(e.target.value)
          setSinkMotor(linkedComponents.get(e.target.value)?.type() === ComponentType.stepperMotor)
        }}
        fullWidth
        autoFocus={false}
        margin="dense"
        variant="standard"
        InputLabelProps={{ shrink: true }}>
        <MenuItem key={""} value={""}>
          Select Controller
        </MenuItem>
        {sinkOptions.map(comp => (
          <MenuItem key={comp.key()} value={comp.key()}>
            {comp.name()}
          </MenuItem>
        ))}
      </TextField>
    );
  }

  const describeSink = (): MeasurementDescriber => {
    const sink = linkedComponents.get(selectedSink);
    return describeMeasurement(
      Measurement.boolean,
      or(sink, Component.create()).settings.type,
      or(sink, Component.create()).settings.subtype
    );
  };

  const dutyCycleInput = () => {
    return (
      <React.Fragment>
        <Grid2 size={{ xs: 4, sm: 4 }}>
          <FormControlLabel
            control={
              <Checkbox
                id="enableDutyCycle"
                checked={dutyCycleEnabled}
                onChange={(_, checked) => {
                  setDutyCycleEnabled(checked)
                }}
                value="enableDutyCycle"
                color="secondary"
              />
            }
            label="Once every"
          />
        </Grid2>
        <Grid2 size={{ xs: 8, sm: 8 }}>
          <TextField
            id="dutyCycle"
            value={dutyCycle}
            onChange={(e) => {
              setDutyCycle(e.target.value)
            }}
            fullWidth
            autoFocus={false}
            margin="dense"
            variant="standard"
            disabled={!dutyCycleEnabled}
            error={isNaN(Number(dutyCycle)) || Number(dutyCycle) < 0}
            InputLabelProps={{
              shrink: true
            }}
            InputProps={{
              endAdornment: <InputAdornment position="end">seconds</InputAdornment>
            }}></TextField>
        </Grid2>
      </React.Fragment>
    );
  };

  const notificationInput = () => {
    return (
      <React.Fragment>
        {resultType !== quack.InteractionResultType.INTERACTION_RESULT_TYPE_REPORT && (
          <Grid2 size={{xs:6, sm:3}}>
            <FormControlLabel
              control={
                <Checkbox
                  id="notificationReports"
                  checked={reporting}
                  onChange={(_, checked) => {
                    setReporting(checked)
                  }}
                  value="notificationReports"
                  color="secondary"
                />
              }
              label="Report"
            />
          </Grid2>
        )}
        <Grid2 size={{xs: resultType !== quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE ? 6 : 12, sm: 3}} >
          <FormControlLabel
            control={
              <Checkbox
                id="interactionNotification"
                checked={notify}
                onChange={(_, checked) => {
                  setNotify(checked)
                }}
                value="interactionNotification"
                color="secondary"
              />
            }
            label="Notify"
            disabled={!reporting}
          />
        </Grid2>
        {notify && (
          <Grid2 size={{ xs: 12, sm: 12 }}>
            <Typography color="textSecondary" variant="subtitle1">
              Everyone with notifications enabled for this device will receive an email and/or SMS
              each time this result occurs
            </Typography>
          </Grid2>
        )}
      </React.Fragment>
    );
  };

  const resultInput = () => {
    return (
      <FormControl component={"fieldset" as "div"} className={classes.borderedContainer} fullWidth>
        <FormLabel component={"legend" as "caption"}>Result</FormLabel>
        <Grid2 container direction="row" spacing={2}>
          <Grid2 size={{ xs: 12, sm: 3 }}>
            <TextField
              select
              id="resultType"
              required={true}
              label=""
              value={resultType}
              onChange={(e) => {
                setResultType(+e.target.value as quack.InteractionResultType)
              }}
              autoFocus={false}
              margin="dense"
              variant="standard"
              fullWidth
              InputLabelProps={{ shrink: true }}>
              <MenuItem value={quack.InteractionResultType.INTERACTION_RESULT_TYPE_REPORT}>Report</MenuItem>
              <MenuItem value={quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET}>Set</MenuItem>
              <MenuItem value={quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE}>Toggle</MenuItem>
              <MenuItem value={quack.InteractionResultType.INTERACTION_RESULT_TYPE_RUN}>Run</MenuItem>
            </TextField>
          </Grid2>
          {resultType === quack.InteractionResultType.INTERACTION_RESULT_TYPE_RUN && (
            <React.Fragment>
              <Grid2 size={{ xs: 12, sm: sinkMotor ? 8 : 4 }}>
                {sinkSelector()}
              </Grid2>
              {sinkMotor && (
                <Grid2 size={{ xs: 12, sm: 5 }} container justifyContent="center">
                  <TextField
                    select
                    id="mode"
                    label=""
                    value={resultMode}
                    onChange={(e) => {
                      setResultMode(+e.target.value)
                    }}
                    fullWidth
                    autoFocus={false}
                    margin="dense"
                    variant="standard"
                    InputLabelProps={{ shrink: true }}>
                    <MenuItem key={"Clockwise"} value={0}>
                      Clockwise
                    </MenuItem>
                    <MenuItem key={"Counter Clockwise"} value={1}>
                      Counter Clockwise
                    </MenuItem>
                  </TextField>
                </Grid2>
              )}
              <Grid2 size={{ xs: 2, sm: 1 }}>
                <Typography variant="subtitle1" color="textSecondary" className={classes.forPrompt}>
                  for
                </Typography>
              </Grid2>
              <Grid2 size={{ xs: 10, sm: sinkMotor ? 6 : 4 }} container justifyContent="center">
                <TextField
                  id="runDuration"
                  required={true}
                  label=""
                  helperText=""
                  error={isNaN(parseFloat(resultValue))}
                  value={resultValue}
                  onChange={(e) => {
                    setResultValue(e.target.value)
                  }}
                  autoFocus={false}
                  margin="dense"
                  variant="standard"
                  fullWidth
                  InputProps={{
                    endAdornment: <InputAdornment position="end">sec</InputAdornment>
                  }}
                  InputLabelProps={{ shrink: true }}
                />
              </Grid2>
            </React.Fragment>
          )}
          {resultType === quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET && (
            <React.Fragment>
              <Grid2 size={{ xs: 12, sm: 4 }}>
                {sinkSelector()}
              </Grid2>
              {linkedComponents.get(selectedSink)?.type() !==
                quack.ComponentType.COMPONENT_TYPE_INTERNAL_FUNCTION && (
                <Grid2 size={{ xs: 2, sm: 1 }}>
                  <Typography
                    variant="subtitle1"
                    color="textSecondary"
                    className={classes.forPrompt}>
                    to
                  </Typography>
                </Grid2>
              )}
              {linkedComponents.get(selectedSink)?.type() !==
                quack.ComponentType.COMPONENT_TYPE_INTERNAL_FUNCTION && (
                <Grid2 size={{ xs: 10, sm: 3 }} container justifyContent="center">
                  <TextField
                    select
                    id="resultValue"
                    label=""
                    value={resultValue}
                    onChange={(e) => {
                      setResultValue(e.target.value)
                    }}
                    fullWidth
                    autoFocus={false}
                    margin="dense"
                    variant="standard"
                    InputLabelProps={{ shrink: true }}>
                    {extension(linkedComponents.get(selectedSink)?.type() ?? quack.ComponentType.COMPONENT_TYPE_INVALID).states.map((state, i) => (
                      <MenuItem key={state} value={i}>
                        {state}
                      </MenuItem>
                    ))}
                  </TextField>
                </Grid2>
              )}
            </React.Fragment>
          )}
          {resultType === quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE && (
            <React.Fragment>
              <Grid2 size={{ xs: 12, sm: 5 }}>
                {sinkSelector()}
              </Grid2>
              <Grid2 size={{ xs: 12, sm: 3 }} container justifyContent="center">
                <FormControlLabel
                  control={
                    <Switch
                      id="resultValue"
                      checked={parseFloat(resultValue) === 1}
                      onChange={(_, checked) => {
                        if(checked){
                          setResultValue('1')
                        }else{
                          setResultValue('0')
                        }
                      }}
                      color="secondary"
                    />
                  }
                  label={describeSink().enumerations()[isNaN(parseFloat(resultValue))?0:parseFloat(resultValue)]}
                />
              </Grid2>
            </React.Fragment>
          )}
          {resultType === quack.InteractionResultType.INTERACTION_RESULT_TYPE_RUN &&
            dutyCycleInput()}
          {notificationInput()}
        </Grid2>
      </FormControl>
    );
  };

  const toggleDaySelected = (day: string, event: any) => {
    let updatedSchedule = cloneDeep(schedule);
    if (event.target.checked) {
      if (!updatedSchedule.weekdays.includes(day)) {
        updatedSchedule.weekdays.push(day);
      }
    } else {
      updatedSchedule.weekdays.splice(updatedSchedule.weekdays.indexOf(day), 1);
    }
    setSchedule(updatedSchedule);
  };

  const daySelector = (day: string, size: any) => {
    //const schedule = or(interaction.settings.schedule, pond.InteractionSchedule.create());
    return (
      <Grid2 container size={{xs: size, sm:1}} alignItems="center">
        <FormControlLabel
          control={
            <Checkbox
              id={day}
              checked={schedule.weekdays.includes(day)}
              onChange={event => toggleDaySelected(day, event)}
              value={day}
              color="secondary"
            />
          }
          label={capitalize(day.substr(0, 2))}
          labelPlacement="bottom"
        />
      </Grid2>
    );
  };

  const setScheduleTime = (id: string, event: any) => {
    let updatedSchedule = cloneDeep(schedule);
    if (id === "shortcut") {
      let value = event.target.value;
      if (value === "allDay") {
        updatedSchedule.timeOfDayStart = "00:00";
        updatedSchedule.timeOfDayEnd = "24:00";
      } else if (value === "before") {
        updatedSchedule.timeOfDayStart = "00:00";
        if (!updatedSchedule.timeOfDayEnd || updatedSchedule.timeOfDayEnd === "24:00") {
          updatedSchedule.timeOfDayEnd = "23:59";
        }
      } else if (value === "after") {
        updatedSchedule.timeOfDayEnd = "24:00";
        if (updatedSchedule.timeOfDayStart === "00:00") {
          updatedSchedule.timeOfDayStart = "00:01";
        }
      } else {
        if (updatedSchedule.timeOfDayStart === "00:00") {
          updatedSchedule.timeOfDayStart = "00:01";
        }
        if (updatedSchedule.timeOfDayEnd === "24:00") {
          updatedSchedule.timeOfDayEnd = "23:59";
        }
      }
    } else {
      let timeOfDay =
        event
          .hour()
          .toString()
          .padStart(2, "0") +
        ":" +
        event
          .minute()
          .toString()
          .padStart(2, "0");
      if (id === "start") {
        updatedSchedule.timeOfDayStart = timeOfDay;
      } else if (id === "end") {
        if (timeOfDay === "00:00") {
          timeOfDay = "24:00";
        }
        updatedSchedule.timeOfDayEnd = timeOfDay;
      }
    }
    updatedSchedule.timezone = moment.tz.guess();
    setSchedule(updatedSchedule);
  };

  const scheduler = () => {
    //let schedule = pond.InteractionSchedule.create();
    let timezone = moment.tz.guess();
    let todStart = "00:00".split(":");
    let todEnd = "23:59".split(":");
    let start = moment
      .tz(timezone)
      .startOf("day")
      .add(todStart[0], "hours")
      .add(todStart[1], "minutes")
      .local();
    let end = moment
      .tz(timezone)
      .startOf("day")
      .add(todEnd[0], "hours")
      .add(todEnd[1], "minutes")
      .local();
    let descriptor = timeOfDayDescriptor(schedule);
    let showStart = descriptor === "after" || descriptor === "from";
    let showEnd = descriptor === "before" || descriptor === "from";
    let showBoth = showStart && showEnd;
    return (
      <FormControl component={"fieldset" as "div"} className={classes.borderedContainer} fullWidth>
        <FormLabel component={"legend" as "caption"}>Schedule</FormLabel>
        <Grid2 container direction="row" spacing={0}>
          {daySelector("sunday", 3)}
          {daySelector("monday", 3)}
          {daySelector("tuesday", 3)}
          {daySelector("wednesday", 3)}
          {daySelector("thursday", 4)}
          {daySelector("friday", 4)}
          {daySelector("saturday", 4)}
        </Grid2>
        <Grid2 container direction="row" spacing={2} alignItems="center">
          <Grid2 size={{xs:12, sm:3}}>
            <TextField
              select
              id="timeOfDayShortcut"
              value={descriptor}
              onChange={(event: any) => setScheduleTime("shortcut", event)}
              fullWidth
              autoFocus={false}
              margin="normal"
              variant="standard"
              InputLabelProps={{ shrink: true }}>
              <MenuItem key="allDay" value="allDay">
                All Day
              </MenuItem>
              <MenuItem key="before" value="before">
                Before
              </MenuItem>
              <MenuItem key="after" value="after">
                After
              </MenuItem>
              <MenuItem key="from" value="from">
                From
              </MenuItem>
            </TextField>
          </Grid2>
          {showStart && (
            <Grid2 size={{xs:5, sm:3}}>
              <TimePicker
                //renderInput={props => <TextField {...props} helperText="" />}
                value={start}
                onChange={(event: any) => setScheduleTime("start", event)}
              />
            </Grid2>
          )}
          {showBoth && (
            <Grid2 size={{xs:2,sm:1}}>
              <Typography
                variant="subtitle1"
                color="textSecondary"
                className={classes.timeRange}
                align="right">
                to
              </Typography>
            </Grid2>
          )}
          {showEnd && (
            <Grid2 size={{xs:5, sm:3}}>
              <TimePicker
                //renderInput={props => <TextField {...props} helperText="" />}
                value={end}
                onChange={(event: any) => setScheduleTime("end", event)}
              />
            </Grid2>
          )}
        </Grid2>
      </FormControl>
    );
  };

  const addInteractionToComponents = () => {
    //array of device and component ids ie, [4:9-5-12, 4:9-5-13, 3:9-5-12]
    let compIds: string[] = [];
    selectedAlertComponents.forEach(comp => {
      let devID = componentDevices.get(comp);
      let component = linkedComponents.get(comp);
      if (devID && component) {
        compIds.push(devID + ":" + component.locationString());
      }
    });
    let newInteraction = pond.InteractionSettings.create();
    newInteraction.conditions = conditions;
    newInteraction.instance = 1;
    newInteraction.schedule = schedule;
    newInteraction.subtype = Interaction.create().subtypeFromNodes(nodeOne, nodeTwo);
    newInteraction.sink = linkedComponents.get(selectedSink)?.location()
    newInteraction.result = pond.InteractionResult.create({
      type: resultType,
      mode: resultMode,
      value: isNaN(parseFloat(resultValue)) ? 0 : parseFloat(resultValue),
      dutyCycle: isNaN(parseFloat(dutyCycle)) ? 0 : parseFloat(dutyCycle)
    });
    newInteraction.notifications = pond.InteractionNotifications.create({
      reports: reporting,
      notify: reporting && notify
    });
    interactionsAPI
      .addInteractionToComponents(compIds, newInteraction, as)
      .then(_resp => {
        openSnack("interaction added to selected components");
      })
      .catch(_err => {
        openSnack("there was a problem adding the interaction to the selected components");
      }).finally(() => {
        close(true)
      });
  };

  return (
      <ResponsiveDialog
        open={open}
        onClose={() => {
          close(false);
        }}>
        <DialogTitle>Set New Alert</DialogTitle>
        <DialogContent>
          {/* Dropdown to select the component type to add the interaction to */}
          <Select
            id="componentType"
            label="Component Type"
            fullWidth
            displayEmpty
            value={newAlertComponentType}
            onChange={e => {
              setNewAlertComponentType(e.target.value as quack.ComponentType);
              setSelectedAlertComponents([]);
              setConditions(initialConditions(e.target.value as quack.ComponentType));
            }}>
            <MenuItem key={0} value={0}>
              Select Component Type
            </MenuItem>
            {validOptions.map(option => (
              <MenuItem key={option.value} value={option.value}>
                {option.label}
              </MenuItem>
            ))}
          </Select>
          {listMatchingComponents()}
          {conditionInput()}
          {device && resultInput()}
          {scheduler()}
        </DialogContent>
        <DialogActions>
          <Button onClick={() => close(false)} variant="contained">
            Cancel
          </Button>
          <Button
            //disabled={selectedAlertComponents.length === 0}
            onClick={addInteractionToComponents}
            variant="contained"
            color="primary">
            Confirm
          </Button>
        </DialogActions>
      </ResponsiveDialog>
  )
}