import {
  Avatar,
  Box,
  Button,
  Card,
  CircularProgress,
  darken,
  DialogActions,
  DialogContent,
  DialogTitle,
  Grid2 as Grid,
  IconButton,
  lighten,
  Link,
  Skeleton,
  Slider,
  Switch,
  TextField,
  Theme,
  Typography,
  useTheme,
} from "@mui/material";
import FullscreenIcon from "@mui/icons-material/Fullscreen";
import FullscreenExitIcon from "@mui/icons-material/FullscreenExit";
import RefreshIcon from "@mui/icons-material/Refresh";
import HumidityIcon from "component/HumidityIcon";
import TemperatureIcon from "component/TemperatureIcon";
import GrainDescriber, { GrainOptions, ToGrainOption } from "grain/GrainDescriber";
import useViewport from "hooks/useViewport";
import { round } from "lodash";
import { Bin, Component, Device } from "models";
import { GetComponentIcon } from "pbHelpers/ComponentType";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { useComponentAPI, useMobile } from "hooks";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { useGlobalState, useSnackbar } from "providers";
import React, { useCallback, useEffect, useState } from "react";
import moment, { Moment } from "moment";
import ResponsiveDialog from "common/ResponsiveDialog";
import { getThemeType } from "theme";
import { or } from "utils";
import { useBinAPI } from "providers/pond/binAPI";
import BindaptIcon from "products/Bindapt/BindaptIcon";
import {
  AccessTime,
  ArrowForwardIos,
  CheckCircleOutline,
  Error,
  InfoOutlined,
  TrendingDown,
  TrendingFlat,
  TrendingUp,
  Warning
} from "@mui/icons-material";
import { Plenum } from "models/Plenum";
import { Pressure } from "models/Pressure";
import { GrainCable } from "models/GrainCable";
import GrainNodeInteractions from "./GrainNodeInteractions";
import GrainTransaction from "grain/GrainTransaction";
import { DevicePreset } from "models/DevicePreset";
import BinSVGV2 from "./BinSVGV2";
import AerationFanIcon from "products/AgIcons/AerationFanIcon";
import ObjectHeaterIcon from "products/Construction/ObjectHeaterIcon";
import { Ambient } from "models/Ambient";
import { ExtractMoisture } from "grain";
import SearchSelect, { Option } from "common/SearchSelect";
import Edit from "@mui/icons-material/Edit";
import { makeStyles } from "@mui/styles";
import ButtonGroup from "common/ButtonGroup";
import ModeChangeDialog from "./conditioning/modeChangeDialog";
import CustomGrainSelector from "grain/CustomGrainSelector";
import BinControllerDisplay from "./BinControllerDisplay";
import { useFullScreen } from "hooks/FullScreenHandle";

const useStyles = makeStyles((theme: Theme) => {
  return ({
    cardContent: {
      padding: theme.spacing(1),
      paddingRight: theme.spacing(0)
    },
    bgItem: {
      background: darken(theme.palette.background.paper, getThemeType() === "light" ? 0.05 : 0.25),
      borderRadius: theme.shape.borderRadius,
      width: "auto",
      marginRight: theme.spacing(1),
      padding: 5
    },
    displayBoxBinLeft: {
      background: darken(theme.palette.background.default, 0.05),
      borderRadius: 5,
      marginRight: -70, //negative margin to extend the box behind the bin svg
      paddingRight: 80, //padding to offset the text and ignore the extension
      paddingTop: 5,
      paddingBottom: 5,
      paddingLeft: 5
    },
    displayBox: {
      background: darken(theme.palette.background.default, 0.05),
      borderRadius: 5,
      padding: 5
    },
    controllerDisplay: {
      display: "flex",
      justifyContent: "space-between",
      paddingLeft: 5,
      paddingRight: 5
    },
    days: {
      margin: theme.spacing(0.5),
      fontSize: "16px"
    },
    avatarIcon: {
      background: "transparent",
      width: theme.spacing(3),
      height: theme.spacing(3),
      margin: "auto",
      marginBottom: "auto"
    },
    selected: {
      backgroundColor: "gold",
      "&.selected": {
        backgroundColor: "gold"
      }
    },
    extraDetails: {
      padding: 1,
      marginTop: theme.spacing(1),
      display: "flex",
      width: "100%",
      flexGrow: 1,
      height: "100%"
    },
    grainOVerlay: {
      position: "absolute",
      height: "10%",
      width: "100%",
      textAlign: "center",
      textShadow: "4px 4px 10px black"
    },
    grainDiff: {
      position: "absolute",
      top: "10%"
    },
    lightBox: {
      background: lighten(theme.palette.background.default, 0.2),
      borderRadius: 10,
      padding: 10,
      margin: 10
    },
    bottomSpacing: {
      marginBottom: theme.spacing(1)
    },
    sliderValLabel: {
      height: 30,
      width: 30,
      left: -5,
      top: -20,
      background: "transparent"
    },
  });
});

const average = (arr: any) => arr.reduce((p: any, c: any) => p + c, 0) / arr.length;

interface GrainConditions {
  tempC: number;
  humidity: number;
  emc: number;
  tempCTrend: number;
  humidityTrend: number;
  emcTrend: number;
}

interface CombinedPlenum {
  tempHumidity?: Plenum,
  pressure?: Pressure
}

interface Props {
  bin: Bin;
  loading: boolean;
  components: Map<string, Component>;
  componentDevices: Map<string, number>;
  devices: Device[];
  plenums?: Plenum[];
  ambient?: Ambient;
  cables?: GrainCable[];
  pressures?: Pressure[];
  refresh: (showSnack?: boolean) => void;
  afterUpdate?(): void;
  preferences?: Map<string, pond.BinComponentPreferences>;
  permissions?: pond.Permission[];
  updateComponentCallback: (componentKey: string) => void;
  binPresets: DevicePreset[];
}

export default function BinVisualizer(props: Props) {
  const {
    bin,
    plenums,
    ambient,
    pressures,
    loading,
    cables,
    components,
    devices,
    preferences,
    componentDevices,
    permissions,
    refresh,
    updateComponentCallback,
    binPresets
  } = props;
  const binAPI = useBinAPI();
  const [{as}] = useGlobalState()
  const isMobile = useMobile();
  const classes = useStyles();
  const theme = useTheme();
  const {fullScreenHandler, FullScreenWrapper} = useFullScreen()
  const viewport = useViewport();
  const { openSnack } = useSnackbar();
  const [fillPercentage, setFillPercentage] = useState<number | null>(0);
  const [lidarBushels, setLidarBushels] = useState<number | undefined>();
  const [lidarPercentage, setLidarPercentage] = useState<number | undefined>();
  const [pendingGrainAmount, setPendingGrainAmount] = useState<number | undefined>();
  const tempColour = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE
  ).colour();
  const humidColour = describeMeasurement(
    quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
    quack.ComponentType.COMPONENT_TYPE_DHT
  ).colour();
  const pressColour = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE).colour();
  const emcColour = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC).colour();
  // const [showInputMoisture, setShowInputMoisture] = useState<boolean>(false);
  const [targetMoisture, setTargetMoisture] = useState(0);
  const [outdoorTemp, setOutdoorTemp] = useState(0);
  const [outdoorHumidity, setOutdoorHumidity] = useState(0);
  const [modeTime, setModeTime] = useState<Moment>(moment());
  const [grainUpdate, setGrainUpdate] = useState<boolean>(false);
  const [openStorageTime, setOpenStorageTime] = useState(false);
  const [sliderColour, setSliderCoulour] = useState("gold");
  const [grainDiff, setGrainDiff] = useState<number>(0);

  const [grainCables, setGrainCables] = useState<GrainCable[]>([]);
  const iOS = typeof window !== "undefined" && /iPad|iPhone|iPod/.test(navigator.userAgent);
  const [nodeDetails, setNodeDetails] = useState(false);
  const [cfmLowOpen, setCFMLowOpen] = useState(false);
  const [cfmHighOpen, setCFMHighOpen] = useState(false);
  const [{ user }] = useGlobalState();
  // const [newPreset, setNewPreset] = useState<pond.BinMode>(pond.BinMode.BIN_MODE_NONE);
  const [newBinMode, setNewBinMode] = useState<pond.BinMode>(pond.BinMode.BIN_MODE_NONE);
  const [selectedCable, setSelectedCable] = useState<GrainCable>();
  const [openNodeDialog, setOpenNodeDialog] = useState(false);
  const [cableDevice, setCableDevice] = useState<Device | undefined>();
  const [selectedNode, setSelectedNode] = useState(0);
  const [devMap, setDevMap] = useState<Map<number, Device>>(new Map<number, Device>());
  //the cables with the highest and lowest temp nodes
  //const [highTempCable, setHighTempCable] = useState<GrainCable>();
  //const [lowTempCable, setLowTempCable] = useState<GrainCable>();
  //the switch value to determine what to display in the grain condition box
  const [valueDisplay, setValueDisplay] = useState<"low" | "avg" | "high">("high");
  //the variables to be able to change the grain type through a unique dialog outside of the settings
  const [grainChangeDialog, setGrainChangeDialog] = useState(false);
  const grainOptions = GrainOptions();
  const [isCustomInventory, setIsCustomInventory] = useState(false);
  const [grainOption, setGrainOption] = useState<Option>();
  const [customTypeName, setCustomTypeName] = useState("");
  const [grainType, setGrainType] = useState<pond.Grain>(pond.Grain.GRAIN_NONE);
  const [storageType, setStorageType] = useState<pond.BinStorage>(
    pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN
  );
  //const [bushPerTonne, setBushPerTonne] = useState("0");
  const [grainSubtype, setGrainSubtype] = useState("");

  const [loadingTrend, setLoadingTrend] = useState(false);
  const [averageConditions, setAverageConditions] = useState<GrainConditions>();
  const [highNodeConditions, setHighNodeConditions] = useState<GrainConditions>();
  const [lowNodeConditions, setLowNodeConditions] = useState<GrainConditions>();

  const [storageDate, setStorageDate] = useState(moment().format("YYYY-MM-DD"));
  const [storageTime, setStorageTime] = useState(moment().format("HH:mm"));

  const [activePlenum, setActivePlenum] = useState<CombinedPlenum | undefined>()
  const [activePlenumIndex, setActivePlenumIndex] = useState(0)
  const [combinedPlenums, setCombinedPlenums] = useState<CombinedPlenum[]>([])

  const [openModeChange, setOpenModeChange] = useState(false)
  const [modeChangeInProgress, setModeChangeInProgress] = useState(false)
  const [newGrainSettings, setNewGrainSettings] = useState<pond.GrainSettings>()

  const [filteredComponents, setFilteredComponents] = useState<Component[]>([])

  useEffect(() => {
    setModeTime(moment(bin.status.lastModeChange));
  }, [bin.status.lastModeChange]);

  useEffect(()=>{
    //match the plenums and pressures based on their location (address)
    let combinedPlenums: CombinedPlenum[] = []
    if (plenums) {
      plenums.forEach(plenum => {
        let newCombinedPlenum: CombinedPlenum = {
          tempHumidity: plenum
        }
        if (pressures) {
          pressures.forEach(pressure => {
            if(plenum.location().address === pressure.location().address){
              newCombinedPlenum.pressure = pressure
            }
          })
        }
        combinedPlenums.push(newCombinedPlenum)
      })
    }
    if (combinedPlenums.length > 0){
      setActivePlenum(combinedPlenums[0])
    }
    setCombinedPlenums(combinedPlenums)
  },[plenums, pressures])

  useEffect(() => {
    setIsCustomInventory(bin.storage() !== pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
    setStorageType(bin.storage());
    // setNewPreset(pond.BinMode.BIN_MODE_NONE);
    if (bin.settings.inventory) {
      setTargetMoisture(bin.settings.inventory.initialMoisture);
      setCustomTypeName(bin.settings.inventory.customTypeName);
      setGrainType(bin.settings.inventory.grainType);
      setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
      //setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
      setGrainSubtype(bin.subtype());
      setNewBinMode(bin.settings.mode);
      setNewGrainSettings(bin.customGrain());
    }
    if (bin.settings) {
      let t = 0
      let h = 0
      if(ambient){
        t = ambient.temperature
        h = ambient.humidity
      }else{
        t = bin.settings.outdoorTemp;//use what is already set in the bin settings
        h = bin.settings.outdoorHumidity
      }

      if (user.settings.temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
        t = CtoF(t);
      }
      setOutdoorTemp(t);
      setOutdoorHumidity(h)
    }
  }, [bin, user, ambient]);

  useEffect(() => {
    //if(loadingTrend) return
    if (cables && cables.length > 0) {
      setGrainCables(cables);
      let trendCables = cables;
      if (bin.key() !== "" && !loadingTrend) {
        setLoadingTrend(true);
        binAPI
          .getBinsTrendData([bin.key()], 7)
          .then(resp => {
            let binTrend = resp.data.trendData[bin.key()];
            //the variables to use to build the average conditions
            let temps: number[] = [];
            let humids: number[] = [];
            let emcs: number[] = [];
            let tempTrends: number[] = [];
            let humidTrends: number[] = [];
            let emcTrends: number[] = [];

            let lowNodeConditions: GrainConditions | undefined = undefined;
            let highNodeConditions: GrainConditions | undefined = undefined;
            let avgConditions: GrainConditions | undefined = undefined;
            trendCables.forEach(cable => {
              //only use the values below the top node
              //because splice mutates the original array make a clone in the cables so the svg still has all of them for display
              //also reverse it so that the node 1 (end of the cable) is in the first position
              let filteredNodes = cable.filteredNodes(true)
              temps.push(...filteredNodes.temps)
              //only push to the humidity values if the cable reads humidities
              if(cable.subType() !== quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_TEMP){
                humids.push(...filteredNodes.humids)
                emcs.push(...filteredNodes.moistures)
              }

              //add the trend data to the proper arrays if the top node is set
              let cableTrendData = binTrend.cableTrend[cable.key()];
              tempTrends.push(cableTrendData.grainCelciusTrend);
              humidTrends.push(cableTrendData.grainHumidityTrend);
              emcTrends.push(cableTrendData.grainEmcTrend);

              //if the lowest temp for this cable is less than the temp in the low node conditions or the low node conditions are not set
              //use this cables lowest node and trend data in the condition
              if (!lowNodeConditions || Math.min(...filteredNodes.temps) < lowNodeConditions.tempC) {
                //determine which node is the coldest so that the data displayed is for the same node
                let lowTempIndex =
                  filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps)) === -1 ? 0 : filteredNodes.temps.indexOf(Math.min(...filteredNodes.temps));
                lowNodeConditions = {
                  tempC: filteredNodes.temps[lowTempIndex],
                  humidity: filteredNodes.humids[lowTempIndex],
                  emc: filteredNodes.moistures[lowTempIndex],
                  tempCTrend: cableTrendData.coldNodeTrend?.tempTrend ?? 0,
                  humidityTrend: cableTrendData.coldNodeTrend?.humidityTrend ?? 0,
                  emcTrend: cableTrendData.coldNodeTrend?.emcTrend ?? 0
                };
              }

              //do the same for the high node
              if (!highNodeConditions || Math.max(...filteredNodes.temps) > highNodeConditions.tempC) {
                let highTempIndex =
                  filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps)) === -1 ? 0 : filteredNodes.temps.indexOf(Math.max(...filteredNodes.temps));
                highNodeConditions = {
                  tempC: filteredNodes.temps[highTempIndex],
                  humidity: filteredNodes.humids[highTempIndex],
                  emc: filteredNodes.moistures[highTempIndex],
                  tempCTrend: cableTrendData.hotNodeTrend?.tempTrend ?? 0,
                  humidityTrend: cableTrendData.hotNodeTrend?.humidityTrend ?? 0,
                  emcTrend: cableTrendData.hotNodeTrend?.emcTrend ?? 0
                };
              }
            });
            
            //set the average conditions
            avgConditions = {
              tempC: average(temps),
              humidity: average(humids),
              emc: average(emcs),
              tempCTrend: average(tempTrends),
              humidityTrend: average(humidTrends),
              emcTrend: average(emcTrends)
            };
            setAverageConditions(avgConditions);
            setLowNodeConditions(lowNodeConditions);
            setHighNodeConditions(highNodeConditions);
          })
          .catch(err => {
            console.log(err);
            openSnack("Failed to retrieve trend data");
          })
          .finally(() => {
            setLoadingTrend(false);
          });
      }
    }
  }, [binAPI, bin, cables, openSnack]); //eslint-disable-line react-hooks/exhaustive-deps

  useEffect(() => {
    let cm = 0;
    //just pull the number from the status
    if (bin.status.distance && bin.status.distance > 0) {
      //note that no conversions are happening as the unit measurement model is not being used so the value will be in cm
      cm = bin.status.distance;
      let height = or(bin.settings.specs?.heightCm, 0);
      let ratio = 1 - cm / height;
      let capacity = or(bin.settings.specs?.bushelCapacity, 0);
      let lidarEstimate = Math.round(capacity * ratio);
      setLidarBushels(lidarEstimate);
      setLidarPercentage(Math.round((lidarEstimate / capacity) * 100));
    } else {
      setLidarBushels(undefined);
      setLidarPercentage(undefined);
    }
  }, [bin]);

  useEffect(() => {
    let newMap = new Map<number, Device>();
    devices.forEach(dev => {
      newMap.set(dev.id(), dev);
    });
    setDevMap(newMap);
  }, [devices]);

  const resetFillPercentage = useCallback(() => {
    if (bin.settings.inventory && bin.settings.specs) {
      const isEmpty = bin.settings.inventory?.empty === true;
      const capacity = bin.settings.specs.bushelCapacity;
      const grainBushels = bin.bushels();
      setSliderCoulour("gold");
      if (!capacity) {
        setFillPercentage(null);
      } else if (isEmpty || !grainBushels) {
        setFillPercentage(0);
      } else {
        setFillPercentage(Math.round((grainBushels / capacity) * 100));
      }
    }
  }, [bin.settings.specs, bin.settings.inventory]);

  useEffect(() => {
    resetFillPercentage();
  }, [resetFillPercentage]);

  const getVolume = (val: number) => {
    if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
      return Math.round(val * 35.239 * 100) / 100;
    } else {
      if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
        return Math.round((val / bin.bushelsPerTonne()) * 100) / 100;
      } else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
        return Math.round((val / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
      }
    }
    return val;
  };

  const getCapacityDisplay = (bushelCapacity: number) => {
    let c = 1;
    if (bushelCapacity !== 0) {
      c = bushelCapacity;
    }
    let capacity = getVolume(c);
    if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
      return " / " + capacity.toLocaleString() + " L";
    }
    if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
      return "mT (" + bin.fillPercent() + "%)";
    } else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
      return "t (" + bin.fillPercent() + "%)";
    } else {
      return " / " + capacity.toLocaleString() + " bu";
    }
  };

  // const grainErrorCheck = () => {
  //   if (isNaN(parseFloat(bushPerTonne))) return true;
  //   return false;
  // };

  const inventoryOverview = () => {
    const capacity = bin.settings.specs?.bushelCapacity ?? 0;
    const grainBushels = bin.bushels();
    const isEmpty = bin.settings.inventory?.empty === true || !grainBushels || grainBushels <= 0;
    const grainSubtype = bin.settings.inventory?.grainSubtype;
    return (
      <Box>
        {/* grain display */}
        <Box display="flex" justifyContent="space-between">
          <Typography variant="subtitle2" color="textPrimary" style={{ fontWeight: 800 }}>
            {isEmpty ? "" : bin.grainName()}
            {grainSubtype !== "" ? " - " + grainSubtype : ""}
          </Typography>
          <Box
            style={{ cursor: "pointer" }}
            onClick={() => {
              setGrainChangeDialog(true);
            }}>
            <Edit />
          </Box>
        </Box>

        {/* box that display capacity */}
        <Box className={classes.bgItem}>
          <div style={{ display: "flex", flexDirection: "row" }}>
            <Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
              {isEmpty ? "Empty" : (grainBushels ? getVolume(grainBushels) : 0).toLocaleString()}
            </Typography>
            <Typography variant="body2">{isEmpty ? "" : getCapacityDisplay(capacity)}</Typography>
          </div>
          {!isEmpty &&
            lidarBushels &&
            bin.inventoryControl() !==
              pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR && (
              <div style={{ display: "flex", flexDirection: "row" }}>
                <Typography variant="body2">
                  {(lidarBushels ? getVolume(lidarBushels) : 0).toLocaleString()} /{" "}
                  {(capacity ? getVolume(capacity) : 0).toLocaleString()} bu (est)
                </Typography>
              </div>
            )}
        </Box>
      </Box>
    );
  };

  const CtoF = (celsius: number) => {
    return Math.round((celsius * (9 / 5) + 32) * 100) / 100;
  };

  const FtoC = (fahrenheit: number) => {
    return Math.round((fahrenheit - 32) * (5 / 9) * 100) / 100;
  };

  const displayTemp = () => {
    let temp = "--";
    let valC: number | undefined;
    switch (valueDisplay) {
      case "avg":
        if (averageConditions && !isNaN(averageConditions.tempC)) {
          valC = averageConditions.tempC;
        }
        break;
      case "high":
        if (highNodeConditions && !isNaN(highNodeConditions.tempC)) {
          valC = highNodeConditions.tempC;
        }
        break;
      case "low":
        if (lowNodeConditions && !isNaN(lowNodeConditions.tempC)) {
          valC = lowNodeConditions.tempC;
        }
        break;
    }
    if (valC) {
      if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
        temp = CtoF(valC).toFixed(1) + "°F";
      } else {
        temp = valC.toFixed(1) + "°C";
      }
    }
    return (
      <Typography
        align="center"
        noWrap
        style={{
          fontSize: isMobile ? "0.85rem" : "1.0rem",
          fontWeight: 650,
          color: tempColour
        }}>
        {temp}
      </Typography>
    );
  };

  const displayHumidityOrEMC = () => {
    let humidity = "--";
    let useEMC = false;
    let val: number | undefined;
    switch (valueDisplay) {
      case "avg":
        if (averageConditions) {
          if (averageConditions.emc) {
            useEMC = true;
            val = averageConditions.emc;
          } else {
            val = averageConditions.humidity;
          }
        }
        break;
      case "high":
        if (highNodeConditions) {
          if (highNodeConditions.emc) {
            useEMC = true;
            val = highNodeConditions.emc;
          } else {
            val = highNodeConditions.humidity;
          }
        }
        break;
      case "low":
        if (lowNodeConditions) {
          if (lowNodeConditions.emc) {
            useEMC = true;
            val = lowNodeConditions.emc;
          } else {
            val = lowNodeConditions.humidity;
          }
        }
        break;
    }
    if (val && !isNaN(val)) {
      humidity = val.toFixed(1) + "%";
    }
    return (
      <Typography
        align="center"
        noWrap
        style={{
          fontSize: isMobile ? "0.85rem" : "1.0rem",
          fontWeight: 650,
          color: useEMC ? emcColour : humidColour
        }}>
        {humidity}
      </Typography>
    );
  };

  const trendArrow = (val: number) => {
    if (val > 0) return <TrendingUp style={{ fill: "green" }} />;
    if (val < 0) return <TrendingDown style={{ fill: "red" }} />;
    return <TrendingFlat />;
  };

  const displayTempTrend = () => {
    let temp = "--";
    let valC: number | undefined;
    switch (valueDisplay) {
      case "avg":
        if (averageConditions && !isNaN(averageConditions.tempCTrend)) {
          valC = averageConditions.tempCTrend;
        }
        break;
      case "high":
        if (highNodeConditions && !isNaN(highNodeConditions.tempCTrend)) {
          valC = highNodeConditions.tempCTrend;
        }
        break;
      case "low":
        if (lowNodeConditions && !isNaN(lowNodeConditions.tempCTrend)) {
          valC = lowNodeConditions.tempCTrend;
        }
        break;
    }
    if (valC) {
      if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
        temp = Math.abs(valC * 1.8).toFixed(1) + "°F"; //since this is a measurement of change a change in 1 degrre celsius is equivalent to 1.8 fahrenheit
      } else {
        temp = Math.abs(valC).toFixed(1) + "°C";
      }
    }
    return (
      <Box height={20} display="flex" justifyContent="center">
        {valC !== undefined && !isNaN(valC) && trendArrow(valC)}
        <Typography
          align="center"
          noWrap
          style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
          {temp}
        </Typography>
      </Box>
    );
  };

  const displayHumidOrEmcTrend = () => {
    let display = "--";
    let val: number | undefined;
    switch (valueDisplay) {
      case "avg":
        if (averageConditions) {
          if (averageConditions.emcTrend) {
            val = averageConditions.emcTrend;
          } else {
            val = averageConditions.humidityTrend;
          }
        }
        break;
      case "high":
        if (highNodeConditions) {
          if (highNodeConditions.emcTrend) {
            val = highNodeConditions.emcTrend;
          } else {
            val = highNodeConditions.humidityTrend;
          }
        }
        break;
      case "low":
        if (lowNodeConditions) {
          if (lowNodeConditions.emcTrend) {
            val = lowNodeConditions.emcTrend;
          } else {
            val = lowNodeConditions.humidityTrend;
          }
        }
        break;
    }
    if (val && !isNaN(val)) {
      display = Math.abs(val).toFixed(1) + "%";
    }
    return (
      <Box height={20} display="flex" justifyContent="center">
        {val !== undefined && !isNaN(val) && trendArrow(val)}
        <Typography
          align="center"
          noWrap
          style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
          {display}
        </Typography>
      </Box>
    );
  };

  //this function is used to reset the state variable to what is in the bin whne they close it without saving any changes
  const closeGrain = () => {
    setIsCustomInventory(bin.storage() !== pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
    setStorageType(bin.storage());
    if (bin.settings.inventory) {
      setTargetMoisture(bin.settings.inventory.initialMoisture);
      setCustomTypeName(bin.settings.inventory.customTypeName);
      setGrainType(bin.settings.inventory.grainType);
      setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
      //setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
      setNewGrainSettings(bin.customGrain())
      setGrainSubtype(bin.subtype());
    }
    setGrainChangeDialog(false);
  };

  const changeGrain = () => {
    const canEdit = permissions ? permissions.includes(pond.Permission.PERMISSION_WRITE) : false;
    return (
      <ResponsiveDialog
        open={grainChangeDialog}
        onClose={() => {
          closeGrain();
        }}>
        <DialogTitle>Change Grain Type</DialogTitle>
        <DialogContent>
          <Grid container justifyContent="space-between" alignItems="center">
            <Grid>
              <Grid container alignItems="center">
                <Grid >Grain</Grid>
                <Grid >
                  <Switch
                    color="default"
                    value={isCustomInventory}
                    checked={isCustomInventory}
                    onChange={(_, checked) => {
                      setIsCustomInventory(checked);
                      //setBushPerTonne("0");
                      setGrainSubtype("");
                      setCustomTypeName("");
                      setGrainOption(ToGrainOption(pond.Grain.GRAIN_NONE));
                      if (checked) {
                        setStorageType(pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN);
                        setGrainType(pond.Grain.GRAIN_CUSTOM);
                        setNewGrainSettings(bin.customGrain())
                      } else {
                        setStorageType(pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
                        setGrainType(pond.Grain.GRAIN_NONE);
                        setNewGrainSettings(undefined)
                      }
                    }}
                    name="storage"
                  />
                </Grid>
                <Grid >Custom</Grid>
              </Grid>
            </Grid>
          </Grid>
          {!isCustomInventory && (
            <Box className={classes.bottomSpacing}>
              <SearchSelect
                label="Type"
                selected={grainOption}
                changeSelection={option => {
                  let newGrainType = option
                    ? pond.Grain[option.value as keyof typeof pond.Grain]
                    : pond.Grain.GRAIN_INVALID;
                  setGrainOption(ToGrainOption(newGrainType));
                  setGrainType(newGrainType);
                  //setBushPerTonne(GrainDescriber(newGrainType).bushelsPerTonne.toFixed(2));
                }}
                group
                disabled={!canEdit}
                options={grainOptions}
              />
            </Box>
          )}
          {isCustomInventory ? (
            <React.Fragment>
              {/* <TextField
                label="Type"
                value={customTypeName}
                type="text"
                onChange={event => {
                  setCustomTypeName(event.target.value);
                }}
                fullWidth
                variant="outlined"
                className={classes.bottomSpacing}
              />
              {storageType !== pond.BinStorage.BIN_STORAGE_FERTILIZER && (
                <TextField
                  label="Bushels Per Tonne"
                  value={bushPerTonne}
                  type="number"
                  error={isNaN(parseFloat(bushPerTonne))}
                  helperText={isNaN(parseFloat(bushPerTonne)) && "Must be a valid number"}
                  onChange={event => {
                    setBushPerTonne(event.target.value);
                  }}
                  fullWidth
                  variant="outlined"
                  className={classes.bottomSpacing}
                />
              )} */}
              <CustomGrainSelector initialGrain={bin.customGrain()} onGrainSettingsChange={settings => {setNewGrainSettings(settings)}}/>
            </React.Fragment>
          ) : (
            <TextField
              label="Grain Variant"
              value={grainSubtype}
              type="text"
              onChange={event => {
                setGrainSubtype(event.target.value);
              }}
              fullWidth
              variant="outlined"
              disabled={!grainOption}
              className={classes.bottomSpacing}
            />
          )}
        </DialogContent>
        <DialogActions>
          <Button
            onClick={() => {
              closeGrain();
            }}>
            Cancel
          </Button>
          <Button
            variant="contained"
            color="primary"
            // disabled={grainErrorCheck()}
            onClick={() => {
              updateBin();
              setGrainChangeDialog(false);
            }}>
            Confirm
          </Button>
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  //the box that displays the grain conditions
  const grainCableOverview = () => {
    return (
      <Box>
        <Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
          Grain Condition
        </Typography>
        <Box className={classes.displayBoxBinLeft}>
          <Grid container alignContent="center" alignItems="center" direction="row">
            <Grid size={{ xs: 2 }}>
              <TemperatureIcon heightWidth={isMobile ? 20 : 25} />
            </Grid>
            <Grid size={{ xs: 4 }}>
              <Box height={20} display="flex" justifyContent="center">
                {displayTemp()}
              </Box>
              <Box display="flex" justifyContent="center">
                <Typography
                  align="center"
                  color="textSecondary"
                  noWrap
                  style={{ fontSize: "0.6rem" }}>
                  {valueDisplay === "low" ? "Low" : valueDisplay === "high" ? "High" : "Average"}
                </Typography>
              </Box>
            </Grid>
            <Grid size={{ xs: 6 }}>
              {displayTempTrend()}
              <Box display="flex" justifyContent="center">
                <Typography
                  align="center"
                  color="textSecondary"
                  noWrap
                  style={{ fontSize: "0.6rem" }}>
                  Past Week
                </Typography>
              </Box>
            </Grid>
          </Grid>
          <Grid container alignContent="center" alignItems="center" direction="row">
            <Grid size={{ xs: 2 }} style={{ paddingLeft: isMobile ? 5 : 8 }}>
              <HumidityIcon height={isMobile ? 20 : 25} />
            </Grid>
            <Grid size={{ xs: 4 }}>
              <Box height={20} display="flex" justifyContent="center">
                {displayHumidityOrEMC()}
              </Box>
              <Box display="flex" justifyContent="center">
                <Typography
                  align="center"
                  color="textSecondary"
                  noWrap
                  style={{ fontSize: "0.6rem" }}>
                  {valueDisplay === "low" ? "Low" : valueDisplay === "high" ? "High" : "Average"}
                </Typography>
              </Box>
            </Grid>
            <Grid size={{ xs: 6 }}>
              {displayHumidOrEmcTrend()}
              <Box display="flex" justifyContent="center">
                <Typography
                  align="center"
                  color="textSecondary"
                  noWrap
                  style={{ fontSize: "0.6rem" }}>
                  Past Week
                </Typography>
              </Box>
            </Grid>
          </Grid>
          <Grid
            container
            direction="row"
            alignContent="center"
            alignItems="center"
            justifyContent="space-between"
            style={{ marginTop: 10 }}>
            <Grid size={{ xs: 4 }}>
              <Button
                onClick={() => {
                  setValueDisplay("low");
                }}
                style={{
                  width: "100%",
                  minWidth: 0,
                  zIndex: valueDisplay === "low" ? 1 : 0,
                  background:
                    valueDisplay === "low" ? "gold" : darken(theme.palette.background.paper, 0.2),
                  borderRadius: 10
                }}>
                <Typography
                  align="center"
                  noWrap
                  style={{
                    fontWeight: 650,
                    fontSize: "0.7rem",
                    color: valueDisplay === "low" ? "black" : "white"
                  }}>
                  Low
                </Typography>
              </Button>
            </Grid>
            <Grid size={{ xs: 4 }}>
              <Button
                onClick={() => {
                  setValueDisplay("avg");
                }}
                style={{
                  width: "100%",
                  minWidth: 0,
                  zIndex: valueDisplay === "avg" ? 1 : 0,
                  background:
                    valueDisplay === "avg" ? "gold" : darken(theme.palette.background.paper, 0.2),
                  borderRadius: 10
                }}>
                <Typography
                  align="center"
                  noWrap
                  style={{
                    fontWeight: 650,
                    fontSize: "0.7rem",
                    color: valueDisplay === "avg" ? "black" : "white"
                  }}>
                  Avg
                </Typography>
              </Button>
            </Grid>
            <Grid size={{ xs: 4 }}>
              <Button
                onClick={() => {
                  setValueDisplay("high");
                }}
                style={{
                  width: "100%",
                  minWidth: 0,
                  zIndex: valueDisplay === "high" ? 1 : 0,
                  background:
                    valueDisplay === "high" ? "gold" : darken(theme.palette.background.paper, 0.2),
                  borderRadius: 10
                }}>
                <Typography
                  align="center"
                  noWrap
                  style={{
                    fontWeight: 650,
                    fontSize: "0.7rem",
                    color: valueDisplay === "high" ? "black" : "white"
                  }}>
                  High
                </Typography>
              </Button>
            </Grid>
          </Grid>
        </Box>
      </Box>
    );
  };

  const plenumOverview = () => {
    return (
      <Box style={{ position: "absolute", bottom: 5, width: "100%" }}>
        <Box display="flex" flexDirection="row" alignItems="center">
        <Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
          Plenum {plenums && plenums?.length > 1 ? activePlenumIndex+1 : ""}
        </Typography>
        {plenums && plenums.length > 1 &&
          <IconButton sx={{background: darken(theme.palette.background.paper, 0.1), marginLeft: 1}} size="small" onClick={()=>{
            let newIndex = activePlenumIndex + 1
            if(newIndex > combinedPlenums.length - 1){
              newIndex = 0
            }
            setActivePlenum(combinedPlenums[newIndex])
            setActivePlenumIndex(newIndex)
          }}>
            <ArrowForwardIos sx={{ fontSize: 15}}/>
          </IconButton>
        }
        </Box>
        <Box
          className={classes.displayBoxBinLeft}
          style={{ marginRight: isMobile ? -70 : -90 }}
          position="relative">
          {activePlenum?.tempHumidity ? (
            <React.Fragment>
              <Grid
                container
                alignContent="center"
                alignItems="center"
                direction="row"
                style={{ paddingLeft: 5 }}>
                <Grid size={{ xs: 2 }}>
                  <Avatar
                    variant="square"
                    src={GetComponentIcon(
                      quack.ComponentType.COMPONENT_TYPE_DHT,
                      undefined,
                      theme.palette.mode
                    )}
                    style={{ height: isMobile ? 20 : 25, width: isMobile ? 20 : 25 }}
                  />
                </Grid>
                <Grid size={{ xs: 5 }}>
                  <Typography
                    align="center"
                    noWrap
                    style={{
                      fontSize: isMobile ? "0.85rem" : "1.0rem",
                      fontWeight: 650,
                      color: tempColour
                    }}>
                    {activePlenum.tempHumidity.getTempString(user.settings.temperatureUnit)}
                  </Typography>
                </Grid>
                <Grid size={{ xs: 5 }}>
                  <Typography
                    align="center"
                    noWrap
                    style={{
                      fontSize: isMobile ? "0.85rem" : "1.0rem",
                      fontWeight: 650,
                      color: humidColour
                    }}>
                    {activePlenum.tempHumidity.getHumidityString()}
                  </Typography>
                </Grid>
              </Grid>
              {/* <Divider
                style={{
                  marginLeft: theme.spacing(1),
                  marginTop: 5,
                  marginBottom: 5,
                  background: "gold",
                  marginRight: -40
                }}
              /> */}
              {pressureOverview()}
            </React.Fragment>
          ) : (
            <Box flexDirection={"row"} display="flex">
              <Avatar variant="square" className={classes.avatarIcon}>
                <BindaptIcon />
              </Avatar>
              <Box textAlign="center" width={"85%"}>
                <Typography>No Plenums found</Typography>
              </Box>
            </Box>
          )}
        </Box>
      </Box>
    );
  };

  const cfmDryWarning = (cfm: number) => {
    if (cfm > 2) {
      return (
        <IconButton onClick={() => setCFMHighOpen(true)}>
          <Error style={{ color: "yellow" }} />
        </IconButton>
      );
    } else if (cfm < 1) {
      return (
        <IconButton onClick={() => setCFMLowOpen(true)}>
          <Warning style={{ color: "red" }} />
        </IconButton>
      );
    } else {
      return (
        <IconButton disabled>
          <CheckCircleOutline style={{ color: "green" }} />
        </IconButton>
      );
    }
  };

  const cfmHighDialog = () => {
    return (
      <ResponsiveDialog
        open={cfmHighOpen}
        onClose={() => {
          setCFMHighOpen(false);
        }}>
        <DialogTitle>CFM Warning</DialogTitle>
        <DialogContent>
          <Typography>Your CFM seems abnormally high</Typography>
          Your fan may have a loose connection
        </DialogContent>
        <DialogActions>
          <Button
            color="primary"
            onClick={() => {
              setCFMHighOpen(false);
            }}>
            Close
          </Button>
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  const cfmLowDialog = () => {
    return (
      <ResponsiveDialog
        open={cfmLowOpen}
        onClose={() => {
          setCFMLowOpen(false);
        }}>
        <DialogTitle>CFM Warning</DialogTitle>
        <DialogContent>
          <Typography>Your CFM is low</Typography>
          Your bin may be too full for your fan, try reducing inventory.
        </DialogContent>
        <DialogActions>
          <Button
            color="primary"
            onClick={() => {
              setCFMLowOpen(false);
            }}>
            Close
          </Button>
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  const pressureOverview = () => {
    return (
      <Grid
        container
        alignContent="center"
        alignItems="center"
        direction="row"
        style={{ paddingLeft: 5, marginTop: 4 }}>
        <Grid size={{ xs: 2 }}>
          <Avatar
            variant="square"
            src={GetComponentIcon(
              quack.ComponentType.COMPONENT_TYPE_PRESSURE,
              undefined,
              theme.palette.mode
            )}
            style={{ height: isMobile ? 20 : 25, width: isMobile ? 20 : 25 }}
          />
        </Grid>
        {activePlenum?.pressure ? (
          <React.Fragment>
            <Grid size={{ xs: 5 }}>
              <Typography
                align="center"
                noWrap
                style={{
                  fontSize: isMobile ? "0.85rem" : "1.0rem",
                  fontWeight: 650,
                  color: pressColour
                }}>
                {activePlenum.pressure.getPressureString(user.settings.pressureUnit)}
              </Typography>
            </Grid>
            {/* <Grid item xs={5}>
              <Typography
                align="center"
                noWrap
                style={{
                  fontSize: isMobile ? "0.85rem" : "1.0rem",
                  fontWeight: 650,
                  color: pressColour
                }}>
                {bin.status.fanCfm.toFixed(0) + "CFM"}
              </Typography>
            </Grid> */}
          </React.Fragment>
        ) : (
          <React.Fragment>
            <Grid size={{ xs: 10 }}>
              <Typography
                color="textSecondary"
                style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
                N/A
              </Typography>
            </Grid>
          </React.Fragment>
        )}
      </Grid>
    );
  };

  const overview = () => {
    return (
      <React.Fragment>
        {inventoryOverview()}
        {grainCableOverview()}
        {plenumOverview()}
      </React.Fragment>
    );
  };

  const getBinSVGHeight = () => {
    if (isMobile) {
      return fullScreenHandler.active ? viewport.height * 0.8 : viewport.width * 0.8;
    }
    return fullScreenHandler.active ? viewport.height * 0.8 : viewport.height * 0.4;
  };

  const visual = () => {
    let diffDisplay = grainDiff;
    let pendingDisplay = pendingGrainAmount;
    if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
      diffDisplay = diffDisplay * 35.239;
      if (pendingDisplay) {
        pendingDisplay = pendingDisplay * 35.239;
      }
    }

    if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
      diffDisplay = diffDisplay / bin.bushelsPerTonne();
      if (pendingDisplay) {
        pendingDisplay = pendingDisplay / bin.bushelsPerTonne();
      }
    }

    if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
      diffDisplay = diffDisplay / (bin.bushelsPerTonne()*0.907);
      if (pendingDisplay) {
        pendingDisplay = pendingDisplay / (bin.bushelsPerTonne()*0.907);
      }
    }

    return (
      <Box display="flex" width={1} justifyContent="flex-end">
        <FullScreenWrapper>
          <Box
            position="relative"
            height={1}
            width={1}
            display="flex"
            justifyContent="center"
            alignItems="center"
            alignContent="flex-end">
            {fullScreenHandler.active && (
              <Box position="absolute" bottom={10} right={10}>
                <IconButton onClick={fullScreenHandler.exit}>
                  <FullscreenExitIcon />
                </IconButton>
              </Box>
            )}
            <Box zIndex={5}>
              <Box>
                {grainDiff > 0 && (
                  <div
                    className={classes.grainOVerlay}
                    style={{
                      top: bin.binShape() === pond.BinShape.BIN_SHAPE_HOPPER_BOTTOM ? "30%" : "35%",
                      color: "#5CE422"
                    }}>
                    <Typography variant={"h5"} style={{ fontWeight: 750 }}>
                      +{diffDisplay.toLocaleString()}
                    </Typography>
                  </div>
                )}
                {pendingDisplay !== undefined && (
                  <div
                    className={classes.grainOVerlay}
                    style={{
                      top: bin.binShape() === pond.BinShape.BIN_SHAPE_HOPPER_BOTTOM ? "40%" : "45%"
                    }}>
                    <Typography variant={"h4"} style={{ fontWeight: 750 }}>
                      {pendingDisplay.toLocaleString()}
                    </Typography>
                  </div>
                )}
                {grainDiff < 0 && (
                  <div
                    className={classes.grainOVerlay}
                    style={{
                      top: bin.binShape() === pond.BinShape.BIN_SHAPE_HOPPER_BOTTOM ? "50%" : "55%",
                      color: "#E42222"
                    }}>
                    <Typography variant={"h5"} style={{ fontWeight: 750 }}>
                      {diffDisplay.toLocaleString()}
                    </Typography>
                  </div>
                )}
              </Box>
              <BinSVGV2
                height={getBinSVGHeight()}
                hasMinHeight
                binShape={bin.settings.specs?.shape}
                fillPercentage={fillPercentage ?? 0}
                lidarEstimate={lidarPercentage}
                cables={grainCables}
                co2Sensors={bin.status.co2}
                highTemp={bin.settings.highTemp}
                lowTemp={bin.settings.lowTemp}
                showTempHum={iOS ? nodeDetails : fullScreenHandler.active}
                grainType={bin.settings.inventory?.grainType}
                isFullScreen={fullScreenHandler.active}
                cableEstimate={bin.settings.autoGrainNode}
                hottestNodeTemp={valueDisplay === "high" ? highNodeConditions?.tempC : undefined}
                coldestNodeTemp={valueDisplay === "low" ? lowNodeConditions?.tempC : undefined}
                cableNodeClicked={(cable, fillNode) => {
                  if (cable) {
                    let devId = componentDevices.get(cable.key());
                    if (devId) {
                      let device = devMap.get(devId);
                      if (device) {
                        setSelectedCable(cable);
                        setSelectedNode(fillNode);
                        setCableDevice(device);
                        //need to set the filtered components so that components on other devices do not show up as options in interaction settings
                        let filtered: Component[] = []
                        components.forEach((component, key) => {
                          if(componentDevices.get(key) === devId){
                            filtered.push(component)
                          }
                        })
                        setFilteredComponents(filtered)
                        setOpenNodeDialog(true);
                      }
                    }
                  }
                }}
                inventoryControl={bin.inventoryControl()}
                customGrain={bin.customGrain()}
              />
            </Box>
          </Box>
        </FullScreenWrapper>
      </Box>
    );
  };

  const valueLabel = (value: number) => {
    return (
      <Box display="flex" sx={{background: sliderColour, height: 30, width: 30, borderRadius: 20}}>
        <Typography sx={{fontSize: 12, fontWeight: 650, color: "black", textAlign: "center", margin: "auto"}}>{value}%</Typography>
      </Box>
    )
  }

  const controls = () => {
    if (bin.settings.inventory?.empty === true) return null;
    const canEdit = permissions ? permissions.includes(pond.Permission.PERMISSION_WRITE) : false;
    return (
      <Box
        height={1}
        width={1}
        display="flex"
        flexDirection="column"
        justifyContent="flex-end"
        alignContent="flex-end">
        {(bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_MANUAL ||
          bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_UNKNOWN) && (
          <React.Fragment>
            <Box display="flex" height={isMobile ? 35 : 40} marginBottom={1}>
              <IconButton
                disabled={!canEdit}
                onClick={() => {
                  setGrainUpdate(true);
                }}
                style={{
                  margin: "auto",
                  backgroundColor: canEdit ? "gold" : "grey",
                  color: "black",
                  height: "100%",
                  width: isMobile ? 35 : 40
                }}>
                <Typography sx={{fontSize: isMobile ? 17 : 20, fontWeight: 650}}>+/-</Typography>
              </IconButton>
            </Box>
            <Box
              height={0.7}
              width={1}
              display="flex"
              justifyContent="center"
              alignContent="flex-end">
              {fillPercentage !== null && (
                <Slider
                  disabled={!canEdit}
                  orientation="vertical"
                  value={fillPercentage}
                  classes={{
                  //   root: classes.sliderRoot,
                  //   rail: classes.sliderRail,
                  //   track: classes.sliderTrack,
                  //   thumb: isMobile ? classes.mobileSliderThumb : classes.sliderThumb,
                    valueLabel: classes.sliderValLabel,
                  }}
                  style={{ height: "100%", color: canEdit ? sliderColour : "gray" }}
                  min={0}
                  max={100}
                  valueLabelDisplay="auto"
                  valueLabelFormat={valueLabel}
                  onChange={(_, value) => {
                    setFillPercentage(value as number);
                    const capacity = bin.settings.specs ? bin.settings.specs.bushelCapacity : 0;
                    const current = bin.bushels()
                    let grainAmount = ((value as number) / 100) * capacity;

                    if (grainAmount < current) {
                      setSliderCoulour("#E42222");
                    } else if (grainAmount > current) {
                      setSliderCoulour("#5CE422");
                    } else {
                      setSliderCoulour("gold");
                    }
                    setGrainDiff(round(grainAmount - current, 0));
                    setPendingGrainAmount(round(grainAmount, 0));
                  }}
                  onChangeCommitted={() => {
                    setGrainUpdate(true);
                  }}
                  aria-labelledby="grain-amount"
                />
              )}
            </Box>
          </React.Fragment>
        )}
        <Box height={0.1} width={1} />
        <Box width={1} textAlign="center">
          {iOS ? (
            <IconButton size="small" onClick={() => setNodeDetails(!nodeDetails)}>
              <InfoOutlined />
            </IconButton>
          ) : (
            <IconButton size="small" onClick={() => fullScreenHandler.enter()}>
              <FullscreenIcon />
            </IconButton>
          )}
        </Box>
      </Box>
    );
  };

  const controllerDisplay = () => {
    return (
      <Box style={{ marginTop: 5 }}>
        <Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
          Controllers
        </Typography>
        <Box className={classes.displayBox}>
          {bin.status.fans.map(fan => {
            let fanComp = components.get(fan.key)
            let device = componentDevices.get(fan.key)
            if(fanComp && device){
              return (
                <BinControllerDisplay key={fanComp.key()} component={fanComp} deviceID={device} currentState={fan.state}/>
              )
            }
          })}
          {bin.status.heaters.map(heater => {
            let heaterComp = components.get(heater.key)
            let device = componentDevices.get(heater.key)
            if(heaterComp && device){
              return (
                <BinControllerDisplay key={heaterComp.key()} component={heaterComp} deviceID={device} currentState={heater.state}/>
              )
            }
          })}
        </Box>
      </Box>
    );
  };

  const fanPerformance = () => {
    let totalCFM = bin.status.fanCfm;
    let bushelCFM = bin.status.cfmPerBushel;
    let emc = ExtractMoisture(
                    bin.grain(),
                    activePlenum?.tempHumidity?.temperature ?? 0,
                    activePlenum?.tempHumidity?.humidity ?? 0,
                    bin.customGrain()
                  )
    return (
      <Box>
        <Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
          Fan Performance
        </Typography>
        {activePlenum?.pressure && activePlenum.pressure.fanId === 0 && !bin.settings.fan?.type && bin.fanID() === 0 && (
          <Typography variant="subtitle2" color="textPrimary" style={{ fontWeight: 600 }}>
            No fans found to calculate CFM
          </Typography>
        )}
        <Box className={classes.displayBox}>
          <Grid
            container
            direction="row"
            alignContent="center"
            alignItems="center"
            justifyContent="space-between">
            <Grid >
              <Box display="flex">
                <Box>
                  <Typography
                    align="center"
                    style={{
                      marginLeft: 10,
                      fontWeight: 650,
                      color: pressColour
                    }}>
                    {totalCFM.toFixed(0) + " CFM"}
                  </Typography>
                  <Typography
                    align="center"
                    style={{
                      marginLeft: 10,
                      fontWeight: 650,
                      color: pressColour
                    }}>
                    {bushelCFM.toFixed(2) + " CFM/bu"}
                  </Typography>
                </Box>
                {cfmDryWarning(bushelCFM)}
              </Box>
            </Grid>
            <Grid>
              {emc !== activePlenum?.tempHumidity?.humidity &&
                <Box className={classes.lightBox}>
                  <Typography align="center" style={{ fontWeight: 650, color: emcColour }}>
                    {emc.toFixed(2)}
                    %
                  </Typography>
                  <Typography align="center" style={{ fontWeight: 650 }}>
                    Plenum EMC
                  </Typography>
                </Box>
              }
            </Grid>
          </Grid>
        </Box>
      </Box>
    );
  };

  const ambientDisplay = () => {
    let emc = ExtractMoisture(
                    bin.grain(),
                    ambient?.temperature ?? 0,
                    ambient?.humidity ?? 0,
                    bin.customGrain()
                  )
    return (
      <Box>
        <Typography style={{ fontSize: isMobile ? "0.85rem" : "1.0rem", fontWeight: 650 }}>
          Ambient
        </Typography>
        <Box className={classes.displayBox}>
          <Grid
            container
            direction="row"
            alignContent="center"
            alignItems="center"
            justifyContent="space-between">
            <Grid >
              <Box display="flex" marginY={1}>
                <TemperatureIcon />
                <Typography
                  style={{
                    marginLeft: 10,
                    fontWeight: 650,
                    color: tempColour
                  }}>
                  {ambient?.getTempString(user.tempUnit())}
                </Typography>
              </Box>
              <Box display="flex" marginY={1}>
                <Box style={{ width: 24, paddingLeft: 6 }}>
                  <HumidityIcon height={24} width={15} />
                </Box>
                <Typography
                  style={{
                    marginLeft: 10,
                    fontWeight: 650,
                    color: humidColour
                  }}>
                  {ambient?.getHumidityString()}
                </Typography>
              </Box>
            </Grid>
            <Grid >
              {emc !== ambient?.humidity &&
                <Box className={classes.lightBox}>
                  <Typography align="center" style={{ fontWeight: 650, color: emcColour }}>
                    {emc.toFixed(2)}
                    %
                  </Typography>
                  <Typography align="center" style={{ fontWeight: 650 }}>
                    Ambient EMC
                  </Typography>
                </Box>
              }
            </Grid>
          </Grid>
        </Box>
      </Box>
    );
  };

  const determineToggle = (binMode: pond.BinMode) => {
    switch (binMode) {
      case pond.BinMode.BIN_MODE_STORAGE:
        return [0]
      case pond.BinMode.BIN_MODE_COOLDOWN:
        return [1]
      case pond.BinMode.BIN_MODE_DRYING:
      case pond.BinMode.BIN_MODE_HYDRATING:
        return [2]
    }
  }

  const binMode = () => {
    const mode = bin.settings.mode;
    return (
      <Box
        display="flex"
        marginBottom={1}
        flexGrow={1}
        height={"100%"}
        width={1}
        justifyContent="space-between"
        alignItems="center"
        alignSelf="flex-end">
        <Typography variant="subtitle1" style={{ fontWeight: 800 }}>
          Bin Mode
        </Typography>
        {modeChangeInProgress &&
          <CircularProgress color="primary" size={25}/>
        }
        <Box id="tour-bin-mode">
          <ButtonGroup 
            disableAll={modeChangeInProgress}
            buttons={[
              {
                title: "Storage",
                function: () => {
                  setModeStorage()
                }
              },
              {
                title: "Cooldown",
                function: () => {
                  setModeCooldown()
                }
              },
              {
                title: bin.settings.inventory && bin.settings.inventory?.initialMoisture < bin.settings.inventory?.targetMoisture ? "Hydrating" : "Drying",
                function: () => {
                  // setShowInputMoisture(true)
                  setModeConditioning() //will set it to either drying or hydrating based on the initial and target moisture
                }
              }
            ]}
            toggledButtons={determineToggle(mode)}
            toggle
            />
        </Box>
      </Box>
    );
  };

  const showDays = (time: Moment) => {
    let now = moment();
    let duration = moment.duration(time.diff(now));
    let days = duration.asDays();
    days = Math.abs(days);
    duration.subtract(moment.duration(days, "days"));
    let hours = duration.hours();
    hours = Math.abs(hours);

    if (bin.settings.mode === pond.BinMode.BIN_MODE_NONE) {
      return (
        <Typography variant="subtitle2" className={classes.days}>
          Select Mode
        </Typography>
      );
    }

    if (days > 50 && bin.settings.mode === pond.BinMode.BIN_MODE_DRYING) {
      return (
        <Typography variant="subtitle2" className={classes.days}>
          Calculating...
        </Typography>
      );
    }

    return (
      <Typography variant="subtitle2" className={classes.days} style={{ fontWeight: 700 }}>
        {Math.floor(days)}d {hours}h
      </Typography>
    );
  };

  const updateStorageTime = () => {
    let status = bin.status;
    let newTimestamp = storageDate + " " + storageTime;
    setModeTime(moment(newTimestamp));
    status.lastModeChange = newTimestamp;
    binAPI
      .updateBinStatus(bin.key(), status, as)
      .then(resp => {
        openSnack("Reset the storage time");
      })
      .catch(err => {
        openSnack("There was a problem resetting the storage time");
      });
  };

  const storageTimeDialog = () => {
    return (
      <ResponsiveDialog open={openStorageTime}>
        <DialogTitle>Set Storage Time</DialogTitle>
        <DialogContent>
          <Typography>Set the date and time that the grain was initially stored</Typography>
          <TextField
            //style={{ width: "45%" }}
            fullWidth
            margin="normal"
            type="date"
            label="Storage Date"
            value={storageDate}
            onChange={e => setStorageDate(e.target.value)}
          />
          <TextField
            //style={{ width: "45%", marginLeft: "10%" }}
            fullWidth
            margin="normal"
            type="time"
            label="Storage Time"
            value={storageTime}
            onChange={e => setStorageTime(e.target.value)}
          />
        </DialogContent>
        <DialogActions>
          <Box display="flex" justifyContent="space-between">
            <Button
              onClick={() => {
                setOpenStorageTime(false);
              }}>
              Close
            </Button>
            <Button
              variant="contained"
              color="primary"
              onClick={() => {
                updateStorageTime();
                setOpenStorageTime(false);
              }}>
              Confirm
            </Button>
          </Box>
        </DialogActions>
      </ResponsiveDialog>
    );
  };

  const dryingEstimate = () => {
    if (
      bin.settings.mode === pond.BinMode.BIN_MODE_DRYING ||
      bin.settings.mode === pond.BinMode.BIN_MODE_HYDRATING
    ) {
      let time = moment(bin.status.targetMoistureEstimation);
      return (
        <Box className={classes.extraDetails}>
          <Box style={{ position: "relative", transform: "translate(50%, 25%)" }}>
            <IconButton style={{ position: "absolute" }} size="small" onClick={() => refresh(true)}>
              <RefreshIcon />
            </IconButton>
          </Box>
          <Box padding={0} style={{ flex: 1, textAlign: "center" }}>
            <Typography variant="body2" style={{ margin: theme.spacing(0.5) }}>
              {bin.settings.mode === pond.BinMode.BIN_MODE_DRYING ? "Drying" : "Hydrating"} Time
              Estimate:
            </Typography>

            {showDays(time)}
          </Box>
        </Box>
      );
    }
    if (bin.settings.mode === pond.BinMode.BIN_MODE_COOLDOWN) {
      return (
        <Box className={classes.extraDetails}>
          <Box style={{ position: "relative", transform: "translate(50%, 25%)" }}>
            <IconButton style={{ position: "absolute" }} size="small" onClick={() => refresh(true)}>
              <RefreshIcon />
            </IconButton>
          </Box>
          <Box padding={0} style={{ flex: 1, textAlign: "center" }}>
            <Typography variant="body2" style={{ margin: theme.spacing(0.5) }}>
              Cooling:
            </Typography>
            {showDays(modeTime)}
          </Box>
        </Box>
      );
    }
    return (
      <Box className={classes.extraDetails}>
        <Box style={{ position: "relative", transform: "translate(0%, 25%)" }}>
          <IconButton style={{ position: "absolute" }} size="small" onClick={() => refresh(true)}>
            <RefreshIcon />
          </IconButton>
        </Box>
        <Box padding={0} style={{ flex: 1, textAlign: "center" }}>
          <Typography variant="body2" style={{ margin: theme.spacing(0.5) }}>
            {bin.settings.mode === pond.BinMode.BIN_MODE_STORAGE ? "In storage for:" : "^"}
          </Typography>
          {showDays(modeTime)}
        </Box>
        <Box style={{ position: "relative", transform: "translate(0%, 25%)" }}>
          <IconButton
            style={{ position: "absolute", right: 1 }}
            size="small"
            onClick={() => {
              setOpenStorageTime(true);
            }}>
            <AccessTime />
          </IconButton>
        </Box>
      </Box>
    );
  };

  const setModeStorage = () => {
    // setNewPreset(pond.BinMode.BIN_MODE_STORAGE);
    setNewBinMode(pond.BinMode.BIN_MODE_STORAGE);
    setOpenModeChange(true)
  };

  const setModeCooldown = () => {
    if (bin.settings.mode === pond.BinMode.BIN_MODE_COOLDOWN) {
      return;
    }
    // setNewPreset(pond.BinMode.BIN_MODE_COOLDOWN);
    setNewBinMode(pond.BinMode.BIN_MODE_COOLDOWN);
    setOpenModeChange(true)
  };

  const setModeConditioning = () => {
    if (
      bin.settings.inventory &&
      bin.settings.inventory?.initialMoisture < bin.settings.inventory?.targetMoisture
    ) {
      // setNewPreset(pond.BinMode.BIN_MODE_HYDRATING);
      setNewBinMode(pond.BinMode.BIN_MODE_HYDRATING);
    } else {
      // setNewPreset(pond.BinMode.BIN_MODE_DRYING);
      setNewBinMode(pond.BinMode.BIN_MODE_DRYING);
    }
    setOpenModeChange(true)
  };

  if (loading) {
    return <Skeleton variant="rectangular" height={460} />;
  }

  const updateBin = () => {
    let b = bin;
    b.settings.storage = storageType;
    if (b.settings.inventory) {
      if (b.settings.inventory.initialMoisture)
        b.settings.inventory.initialMoisture = targetMoisture;
      //update all the grain stuff
      b.settings.inventory.grainType = grainType;
      b.settings.inventory.customTypeName = customTypeName;
      b.settings.inventory.bushelsPerTonne = GrainDescriber(grainType).bushelsPerTonne
      // b.settings.inventory.bushelsPerTonne = isNaN(parseFloat(bushPerTonne))
      //   ? 0
      //   : parseFloat(bushPerTonne);
      b.settings.inventory.grainSubtype = grainSubtype;
      b.settings.inventory.customGrain = newGrainSettings
    }

    if (b.settings.outdoorTemp !== undefined) {
      let t = outdoorTemp;
      if (user.settings.temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
        t = FtoC(outdoorTemp);
      }
      b.settings.outdoorTemp = t;
    }
    if (b.settings.outdoorHumidity !== undefined)
      b.settings.outdoorHumidity = outdoorHumidity;

    if (b.settings.mode != newBinMode){
      if(b.settings.inventory){
        b.settings.inventory.initialTimestamp = moment().format();
      }
      b.settings.mode = newBinMode;
    }
    binAPI.updateBin(bin.key(), b.settings, as).then(resp => {
      refresh();
    });
  };

  return (
    <Card raised className={classes.cardContent}>
      {cfmLowDialog()}
      {cfmHighDialog()}
      {changeGrain()}
      {storageTimeDialog()}
      <ModeChangeDialog 
        binKey={bin.key()}
        binMode={newBinMode}
        grain={bin.settings.inventory?.grainType}
        devices={devices}
        open={openModeChange}
        binCables={cables}
        presets={binPresets}
        compDevMap={componentDevices}
        preferences={preferences}
        onClose={(refresh) => {
          setOpenModeChange(false)
          if(refresh) updateBin();
        }}
        defaultTargetMoisture={bin.settings.inventory?.initialMoisture}
        defaultOutdoorTemp={outdoorTemp}
        defaultOutdoorHumidity={outdoorHumidity}
        changeTargetMoisture={newMoisture => {
          setTargetMoisture(newMoisture)
        }}
        changeOutdoorTemp={newTemp => {
          setOutdoorTemp(newTemp)
        }}
        changeOutdoorHumidity={newHumidity => {
          setOutdoorHumidity(newHumidity)
        }}
        startChange={() => {
          setModeChangeInProgress(true)
        }}
        changeComplete={() => {
          setModeChangeInProgress(false)
        }}

      />
      <Box paddingRight={1}>
        {binMode()}
        <Grid container justifyContent="flex-start" alignItems="stretch">
          <Grid size={5.5} style={{ position: "relative" }}>
            {overview()}
          </Grid>
          <Grid size={5} style={{ position: "relative" }}>
            {visual()}
          </Grid>
          <Grid size={1.5} >{controls()}</Grid>
        </Grid>
        {plenums && pressures && fanPerformance()}
        {ambient && ambientDisplay()}
        {(bin.status.fans.length > 0 || bin.status.heaters.length > 0) && controllerDisplay()}
        {dryingEstimate()}
      </Box>
      <GrainTransaction
        open={grainUpdate}
        mainObject={bin}
        grainAdjustment={grainDiff}
        close={() => {
          setGrainUpdate(false);
          setPendingGrainAmount(undefined);
          resetFillPercentage();
          setGrainDiff(0);
        }}
        callback={props.afterUpdate}
      />
      {selectedCable && cableDevice && (
        <GrainNodeInteractions
          binKey={bin.key()}
          interactionComponents={filteredComponents}
          grain={bin.grain()}
          cable={selectedCable}
          open={openNodeDialog}
          device={cableDevice}
          selectedNode={selectedNode}
          close={() => {
            setOpenNodeDialog(false);
          }}
          permissions={permissions ?? []}
          updateComponentCallback={updateComponentCallback}
        />
      )}
      <div style={{ bottom: "0px" }}></div>
    </Card>
  );
}
