import {
  Box,
  Button,
  Card,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Grid2 as Grid,
  InputAdornment,
  MenuItem,
  Slider,
  TextField,
  Typography
} from "@mui/material";
import { useMobile } from "hooks";
import { cloneDeep } from "lodash";
import { DevicePreset } from "models/DevicePreset";
import { ObjectTypeString } from "objects/ObjectDescriber";
import { pond } from "protobuf-ts/pond";
import { useGlobalState, useSnackbar } from "providers";
import { useDevicePresetAPI } from "providers/pond/devicePresetAPI";
import React, { useEffect, useState } from "react";

interface Props {
  preset: DevicePreset;
  existing?: boolean;
  objectKey?: string;
  objectType?: pond.ObjectType;
  addCallback?: (preset: DevicePreset, tempKey: string) => void;
  removeCallback?: (preset: DevicePreset) => void;
  updateCallback?: (oldPreset: DevicePreset, newPreset: DevicePreset) => void;
}

export default function DevicePresetCard(props: Props) {
  const {
    preset,
    existing,
    objectKey,
    objectType,
    addCallback,
    removeCallback,
    updateCallback
  } = props;
  const devicePresetAPI = useDevicePresetAPI();
  const [presetName, setPresetName] = useState("");
  const [presetType, setPresetType] = useState<pond.PresetType>(1);
  const [controllerType, setControllerType] = useState<pond.ControllerType>(1);
  const [openDeleteConfirmation, setOpenDeleteConfirmation] = useState(false);
  const { openSnack } = useSnackbar();
  const [tempString, setTempString] = useState("0");
  const [tempC, setTempC] = useState(0);
  const [humString, setHumString] = useState("0");
  const [hum, setHum] = useState(0);
  const isMobile = useMobile();
  const [{user}] = useGlobalState();

  useEffect(() => {
    setPresetName(preset.name);
    setPresetType(preset.settings.type);
    setControllerType(preset.settings.controller);
    setTempC(preset.settings.temperature);
    setHum(preset.settings.humidity);
    setHumString(preset.settings.humidity.toString());
    let displayTemp = preset.settings.temperature.toString();
    if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
      displayTemp = ((preset.settings.temperature * 9) / 5 + 32).toFixed();
    }
    setTempString(displayTemp);
  }, [preset, user]);

  const saveNewPreset = () => {
    let typestring;
    if (objectType) {
      typestring = ObjectTypeString(objectType);
    }
    let p = preset;
    p.name = presetName;
    p.settings.type = presetType;
    p.settings.controller = controllerType;
    p.settings.temperature = tempC;
    p.settings.humidity = hum;

    devicePresetAPI
      .addDevicePreset(p.name, p.settings, objectKey, typestring)
      .then(resp => {
        //get the temp key from the preset
        let temp = p.key;
        //update the key in the preset with the key that came back from the add
        p.key = resp.data.key;
        //use the callback function passing in the preset and the temp key
        if (addCallback) {
          addCallback(p, temp);
        }
        openSnack("New preset saved");
      })
      .catch(err => {
        openSnack("Failed to save new preset");
      });
  };

  const updatePreset = () => {
    let newPreset = cloneDeep(preset);
    let oldPreset = cloneDeep(preset);
    newPreset.name = presetName;
    newPreset.settings.type = presetType;
    newPreset.settings.controller = controllerType;
    newPreset.settings.temperature = tempC;
    newPreset.settings.humidity = hum;

    devicePresetAPI
      .updateDevicePreset(newPreset.key, newPreset.name, newPreset.settings)
      .then(resp => {
        if (updateCallback) {
          updateCallback(oldPreset, newPreset);
        }
        openSnack("Preset Updated");
      })
      .catch(err => {
        openSnack("There was a problem updating the preset");
      });
  };

  const removePreset = () => {
    devicePresetAPI
      .removeDevicePreset(preset.key)
      .then(resp => {
        openSnack("Preset has been deleted");
        setOpenDeleteConfirmation(false);
        if (removeCallback) {
          removeCallback(preset);
        }
      })
      .catch(err => {
        openSnack("There was a problem deleting this preset");
      });
  };

  const deleteConfirmation = () => {
    return (
      <Dialog
        open={openDeleteConfirmation}
        onClose={() => {
          setOpenDeleteConfirmation(false);
        }}>
        <DialogTitle>Delete Preset</DialogTitle>
        <DialogContent>This action will delete the selected preset</DialogContent>
        <DialogActions>
          <Button
            onClick={() => {
              setOpenDeleteConfirmation(false);
            }}>
            Cancel
          </Button>
          <Button
            variant="contained"
            color="primary"
            onClick={() => {
              removePreset();
            }}>
            Confirm
          </Button>
        </DialogActions>
      </Dialog>
    );
  };

  const presetComparitors = () => {
    if (controllerType === pond.ControllerType.CONTROLLER_TYPE_HEATER) {
      switch (presetType) {
        case pond.PresetType.PRESET_TYPE_DRYING:
          return { temp: "below", hum: "above" };
        case pond.PresetType.PRESET_TYPE_COOLING:
          return { temp: "below", hum: "above" };
      }
    } else {
      //the controller type is a fan
      switch (presetType) {
        case pond.PresetType.PRESET_TYPE_DRYING:
          return { temp: "above", hum: "below" };
        case pond.PresetType.PRESET_TYPE_COOLING:
          return { temp: "below", hum: "below" };
        case pond.PresetType.PRESET_TYPE_HYDRATING:
          return { temp: "below", hum: "above" };
      }
    }
    //replace having a default case with final return
    return { temp: "", hum: "" };
  };

  return (
    <Card raised style={{ padding: 10, width: "100%" }}>
      {deleteConfirmation()}
      <Grid container direction="row" alignContent="center" alignItems="center">
        <Grid size={{xs:12, sm:6}}>
          <TextField
            variant="outlined"
            margin="normal"
            style={{ width: "100%" }}
            value={presetName}
            onChange={e => {
              setPresetName(e.target.value);
            }}
          />
        </Grid>
        <Grid size={{xs:12, sm:6}}>
          {presetType !== pond.PresetType.PRESET_TYPE_UNKNOWN &&
            controllerType !== pond.ControllerType.CONTROLLER_TYPE_UNKNOWN && (
              <Box paddingLeft={2}>
                <Typography>
                  Toggle{" "}
                  {controllerType === pond.ControllerType.CONTROLLER_TYPE_HEATER ? "heater" : "fan"}{" "}
                  on when temperature {presetComparitors().temp} and humidity{" "}
                  {presetComparitors().hum} set points
                </Typography>
              </Box>
            )}
        </Grid>
        <Grid size={6}>
          {/* type */}
          <TextField
            style={{ width: "100%", marginRight: 5 }}
            margin="normal"
            select
            label="Type"
            variant="outlined"
            value={presetType}
            onChange={e => {
              setPresetType(+e.target.value as pond.PresetType);
            }}>
            <MenuItem
              key={pond.PresetType.PRESET_TYPE_UNKNOWN}
              value={pond.PresetType.PRESET_TYPE_UNKNOWN}>
              Mode For Preset
            </MenuItem>
            <MenuItem
              key={pond.PresetType.PRESET_TYPE_DRYING}
              value={pond.PresetType.PRESET_TYPE_DRYING}>
              Drying
            </MenuItem>
            <MenuItem
              key={pond.PresetType.PRESET_TYPE_COOLING}
              value={pond.PresetType.PRESET_TYPE_COOLING}>
              Cooling
            </MenuItem>
            <MenuItem
              key={pond.PresetType.PRESET_TYPE_HYDRATING}
              value={pond.PresetType.PRESET_TYPE_HYDRATING}>
              Hydrating
            </MenuItem>
          </TextField>
        </Grid>
        <Grid size={6}>
          {/* controller type */}
          <TextField
            style={{ width: "100%", marginLeft: 5 }}
            margin="normal"
            select
            label="Controller Type"
            variant="outlined"
            value={controllerType}
            onChange={e => {
              setControllerType(+e.target.value as pond.ControllerType);
            }}>
            <MenuItem
              key={pond.ControllerType.CONTROLLER_TYPE_UNKNOWN}
              value={pond.ControllerType.CONTROLLER_TYPE_UNKNOWN}>
              Controller For Preset
            </MenuItem>
            <MenuItem
              key={pond.ControllerType.CONTROLLER_TYPE_HEATER}
              value={pond.ControllerType.CONTROLLER_TYPE_HEATER}>
              Heater
            </MenuItem>
            <MenuItem
              key={pond.ControllerType.CONTROLLER_TYPE_FAN}
              value={pond.ControllerType.CONTROLLER_TYPE_FAN}>
              Fan
            </MenuItem>
          </TextField>
        </Grid>
        {/* temp slider */}
        {isMobile ? (
          <Grid size={12}>
            <Box
              display="flex"
              alignContent="center"
              alignItems="center"
              justifyContent="space-between">
              <Typography>Temperature</Typography>
              <TextField
                style={{ marginLeft: 5 }}
                margin="dense"
                variant="outlined"
                type="number"
                InputProps={{
                  endAdornment: (
                    <InputAdornment position="end">
                      {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
                        ? "°F"
                        : "°C"}
                    </InputAdornment>
                  )
                }}
                error={isNaN(+tempString)}
                value={tempString}
                onChange={e => {
                  if (!isNaN(+e.target.value)) {
                    let temp = +e.target.value;
                    if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
                      temp = Math.round((((temp - 32) * 5) / 9) * 10) / 10;
                    }
                    setTempC(temp);
                  }
                  setTempString(e.target.value);
                }}
              />
            </Box>
            <Box paddingLeft={2} paddingRight={2}>
              <Slider
                //orientation="vertical"
                value={tempC}
                min={-40}
                max={40}
                valueLabelDisplay="auto"
                valueLabelFormat={value => {
                  if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
                    return ((value * 9) / 5 + 32).toFixed() + "°F";
                  }
                  return value.toFixed() + "°C";
                }}
                onChange={(_, value) => {
                  setTempC(value as number);
                  setTempString(value.toString());
                }}
              />
            </Box>
          </Grid>
        ) : (
          <React.Fragment>
            <Grid size={2}>
              <Typography>Temperature</Typography>
            </Grid>
            <Grid size={7}>
              <Box paddingRight={2}>
                <Slider
                  //orientation="vertical"
                  value={tempC}
                  min={-40}
                  max={40}
                  valueLabelDisplay="auto"
                  valueLabelFormat={value => {
                    if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
                      return ((value * 9) / 5 + 32).toFixed() + "°F";
                    }
                    return value.toFixed() + "°C";
                  }}
                  onChange={(_, value) => {
                    setTempC(value as number);
                    setTempString(value.toString());
                  }}
                />
              </Box>
            </Grid>
            <Grid size={3}>
              <TextField
                style={{ width: "100%" }}
                margin="dense"
                variant="outlined"
                type="number"
                InputProps={{
                  endAdornment: (
                    <InputAdornment position="end">
                      {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
                        ? "°F"
                        : "°C"}
                    </InputAdornment>
                  )
                }}
                error={isNaN(+tempString)}
                value={tempString}
                onChange={e => {
                  if (!isNaN(+e.target.value)) {
                    let temp = +e.target.value;
                    if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
                      temp = Math.round((((temp - 32) * 5) / 9) * 10) / 10;
                    }
                    setTempC(temp);
                  }
                  setTempString(e.target.value);
                }}
              />
            </Grid>
          </React.Fragment>
        )}
        {/* humidity slider */}
        {isMobile ? (
          <Grid size={12}>
            <Box
              display="flex"
              alignContent="center"
              alignItems="center"
              justifyContent="space-between">
              <Typography>Humidity</Typography>
              <TextField
                style={{ marginLeft: 5 }}
                margin="dense"
                variant="outlined"
                type="number"
                InputProps={{
                  endAdornment: <InputAdornment position="end">%</InputAdornment>
                }}
                error={isNaN(+humString)}
                value={humString}
                onChange={e => {
                  if (!isNaN(+humString)) {
                    setHum(+e.target.value);
                  }
                  setHumString(e.target.value);
                }}
              />
            </Box>
            <Box paddingLeft={2} paddingRight={2}>
              <Slider
                //orientation="vertical"
                value={hum}
                min={0}
                max={100}
                valueLabelDisplay="auto"
                valueLabelFormat={value => value.toFixed() + "%"}
                onChange={(_, value) => {
                  setHum(value as number);
                  setHumString(value.toString());
                }}
              />
            </Box>
          </Grid>
        ) : (
          <React.Fragment>
            <Grid size={2}>
              <Typography>Humidity</Typography>
            </Grid>
            <Grid size={7}>
              <Box paddingRight={2}>
                <Slider
                  //orientation="vertical"
                  value={hum}
                  min={0}
                  max={100}
                  valueLabelDisplay="auto"
                  valueLabelFormat={value => value.toFixed() + "%"}
                  onChange={(_, value) => {
                    setHum(value as number);
                    setHumString(value.toString());
                  }}
                />
              </Box>
            </Grid>
            <Grid size={3}>
              <TextField
                style={{ width: "100%" }}
                margin="dense"
                variant="outlined"
                type="number"
                InputProps={{
                  endAdornment: <InputAdornment position="end">%</InputAdornment>
                }}
                error={isNaN(+humString)}
                value={humString}
                onChange={e => {
                  if (!isNaN(+humString)) {
                    setHum(+e.target.value);
                  }
                  setHumString(e.target.value);
                }}
              />
            </Grid>
          </React.Fragment>
        )}
      </Grid>
      <Box display="flex" justifyContent="flex-end" alignContent="flex-end" marginTop={1}>
        {existing && (
          <Button
            variant="contained"
            style={{ background: "red" }}
            onClick={() => {
              setOpenDeleteConfirmation(true);
            }}>
            Delete
          </Button>
        )}
        {existing ? (
          <Button
            style={{ marginLeft: 5 }}
            variant="contained"
            color="primary"
            onClick={() => {
              updatePreset();
            }}>
            Update
          </Button>
        ) : (
          <Button
            disabled={
              presetType === pond.PresetType.PRESET_TYPE_UNKNOWN ||
              controllerType === pond.ControllerType.CONTROLLER_TYPE_UNKNOWN
            }
            onClick={() => saveNewPreset()}
            variant="contained"
            color="primary">
            Save
          </Button>
        )}
      </Box>
    </Card>
  );
}
