import { AccessTime, MoreVert } from "@mui/icons-material";
import { Avatar, Box, Button, Card, Checkbox, FormControlLabel, Grid2, IconButton, Menu, MenuItem, Typography, useTheme } from "@mui/material";
import BinSensorCard from "bin/BinSensorCard";
import { GetDefaultDateRange } from "common/time/DateRange";
import { ExtractMoisture } from "grain";
import { useMobile, useThemeType } from "hooks";
import { Bin, Component } from "models";
import { Ambient } from "models/Ambient";
import { CO2 } from "models/CO2";
import { Controller } from "models/Controller";
import { GrainCable } from "models/GrainCable";
import { Headspace } from "models/Headspace";
import { Plenum } from "models/Plenum";
import { Pressure } from "models/Pressure";
import moment, { Moment } from "moment";
import { GetComponentIcon } from "pbHelpers/ComponentType";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { useBinAPI, useComponentAPI, useGlobalState, useSnackbar } from "providers";
import React, { useEffect, useState } from "react";
import { avg } from "utils";
import BinSensorGraph from "./graphs/BinSensorGraph";
import TimeBar from "common/time/TimeBar";

interface Props {
    bin: Bin
    components: Map<string, Component>;
    componentDevices: Map<string, number>;
    preferences?: Map<string, pond.BinComponentPreferences>;
    setPreferences: React.Dispatch<
      React.SetStateAction<Map<string, pond.BinComponentPreferences> | undefined>
    >;
    
}

export default function BinSensorsDisplay(props: Props){
    const {bin, components, componentDevices, preferences, setPreferences} = props
    const themeType = useThemeType()
    const [{user, as}] = useGlobalState()
    const binAPI = useBinAPI()
    const componentAPI = useComponentAPI()
    const theme = useTheme()
    const snackbar = useSnackbar()
    const [cables, setCables] = useState<GrainCable[]>([])
    const [plenums, setPlenums] = useState<Plenum[]>([])
    const [ambient, setAmbient] = useState<Ambient[]>([])
    const [pressures, setPressures] = useState<Pressure[]>([])
    const [fans, setFans] = useState<Controller[]>([])
    const [heaters, setHeaters] = useState<Controller[]>([])
    //the above component preferences all have only components that are one type of sensor, however headspace has components of three different sensors T/H, CO2, and Lidar
    const [headspaceTH, setHeadspaceTH] = useState<Headspace[]>([]) //the components in the headspace that measure temp/humidity
    const [headspaceCO2, setHeadspaceCO2] = useState<CO2[]>([]) //the CO2 components in the headspace
    const [headspaceLidar, setHeadspaceLidar] = useState<Component[]>([]) //the lidar components in the headspace

    const [unassignedComponents, setUnassignedComponents] = useState<Component[]>([])

    //using counts so i dont have to have to check multiple arrays for sensors and controllers
    const [sensorCount, setSensorCount] = useState(0)
    const [controllerCount, setControllerCount] = useState(0)

    const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
    //only used to determine what preferences are options for the selected component ie. DHT can be a plenum or a headspace
    const [selectedComponentType, setSelectedComponentType] = useState<
      quack.ComponentType | undefined
    >(undefined);
    const [componentUnassigned, setComponentUnnassigned] = useState(false);
    const [selectedComponentKey, setSelectedComponentKey] = useState("");
    const [selectedComponentSubtype, setSelectedComponentSubtype] = useState(0);
    const [selectedComponentTopNode, setSelectedComponentTopNode] = useState(0);
    const [showGraphs, setShowGraphs] = useState(false);
    const defaultDateRange = GetDefaultDateRange();
    const [startDate, setStartDate] = useState<Moment>(defaultDateRange.start);
    const [endDate, setEndDate] = useState<Moment>(defaultDateRange.end);
    const [filterNodes, setFilterNodes] = useState(true)
    const isMobile = useMobile()

    //organize the components into the correct 'positions' using the bins preferences
    useEffect(()=>{
        let unassigned: Component[] = []
        let cables: GrainCable[] = []
        let plenums: Plenum[] = []
        let ambients: Ambient[] = []
        let pressures: Pressure[] = []
        let fans: Controller[] = []
        let heaters: Controller[] = []
        let headspaceTH: Headspace[] = []
        let headspaceCO2: CO2[] = []
        let headspaceLidar: Component[] = []
        let sensorCount = 0
        let controllerCount = 0

        components.forEach(comp => {
            if(preferences){
                let pref = preferences.get(comp.key())
                switch(pref?.type){
                    case pond.BinComponent.BIN_COMPONENT_GRAIN_CABLE:
                        cables.push(GrainCable.create(comp))
                        sensorCount++
                        break;
                    case pond.BinComponent.BIN_COMPONENT_PLENUM:
                        plenums.push(Plenum.create(comp))
                        sensorCount++
                        break;
                    case pond.BinComponent.BIN_COMPONENT_AMBIENT:
                        ambients.push(Ambient.create(comp))
                        sensorCount++
                        break;
                    case pond.BinComponent.BIN_COMPONENT_PRESSURE:
                        pressures.push(Pressure.create(comp))
                        sensorCount++
                        break;
                    case pond.BinComponent.BIN_COMPONENT_FAN:
                        fans.push(Controller.create(comp))
                        controllerCount++
                        break;
                    case pond.BinComponent.BIN_COMPONENT_HEATER:
                        heaters.push(Controller.create(comp))
                        controllerCount++
                        break;
                    case pond.BinComponent.BIN_COMPONENT_HEADSPACE:
                        if (comp.type() === quack.ComponentType.COMPONENT_TYPE_DHT) {
                          headspaceTH.push(Headspace.create(comp));
                        } else if (comp.type() === quack.ComponentType.COMPONENT_TYPE_LIDAR) {
                          headspaceLidar.push(comp);
                        } else if (comp.type() === quack.ComponentType.COMPONENT_TYPE_CO2) {
                          let coComp = CO2.create(comp)
                          headspaceCO2.push(coComp);
                        }
                        sensorCount++
                        break;
                    default:
                        unassigned.push(comp)
                }
            }else{
                unassigned.push(comp)
            }
        })
        // console.log(cables)
        // console.log(unassigned)
        setSensorCount(sensorCount)
        setControllerCount(controllerCount)
        setCables(cables)
        setPlenums(plenums)
        setPressures(pressures)
        setAmbient(ambients)
        setFans(fans)
        setHeaters(heaters)
        setHeadspaceTH(headspaceTH)
        setHeadspaceCO2(headspaceCO2)
        setHeadspaceLidar(headspaceLidar)
        setUnassignedComponents(unassigned)
    },[components, preferences])

    const selectType = (component: string, type: pond.BinComponent, topNode?: number) => {
      setAnchorEl(null);
      if (!preferences) return
      let p = preferences.get(component);
      if (p) {
        p.type = type;
        p.node = topNode ?? 0;
        binAPI
          .updateComponentPreferences(bin.key(), component, p, as)
          .then(() => {
            snackbar.success("Component preferences updated");
            preferences.set(component, p!);
            setPreferences(new Map(preferences));
          })
          .catch(() => {
            snackbar.error("Component preference update failed");
          });
      }
    };

    const getOptions = () => {
        let options: JSX.Element[] = [];
    
        if (!componentUnassigned) {
          options.push(
            <MenuItem
              key="remove"
              onClick={() => {
                selectType(selectedComponentKey, pond.BinComponent.BIN_COMPONENT_UNKNOWN);
              }}>
              Remove
            </MenuItem>
          );
        }
        if (
          selectedComponentType === quack.ComponentType.COMPONENT_TYPE_DHT ||
          selectedComponentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE
        ) {
          options.push(
            <MenuItem
              key="ambientOption"
              onClick={() => {
                selectType(selectedComponentKey, pond.BinComponent.BIN_COMPONENT_AMBIENT);
              }}>
              Ambient
            </MenuItem>
          );
          options.push(
            <MenuItem
              key="plenumOption"
              onClick={() => {
                selectType(selectedComponentKey, pond.BinComponent.BIN_COMPONENT_PLENUM);
              }}>
              Plenum
            </MenuItem>
          );
        }
        if (
          selectedComponentType === quack.ComponentType.COMPONENT_TYPE_DHT ||
          selectedComponentType === quack.ComponentType.COMPONENT_TYPE_LIDAR ||
          selectedComponentType === quack.ComponentType.COMPONENT_TYPE_CO2
        ) {
          options.push(
            <MenuItem
              key="headspaceOption"
              onClick={() => {
                selectType(selectedComponentKey, pond.BinComponent.BIN_COMPONENT_HEADSPACE);
              }}>
              Headspace
            </MenuItem>
          );
        }
        if (
          selectedComponentType === quack.ComponentType.COMPONENT_TYPE_PRESSURE ||
          selectedComponentType === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE
        ) {
          options.push(
            <MenuItem
              key="pressureOption"
              onClick={() => {
                selectType(selectedComponentKey, pond.BinComponent.BIN_COMPONENT_PRESSURE);
              }}>
              Plenum Pressure
            </MenuItem>
          );
        }
        if (selectedComponentType === quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE) {
          options.push(
            <MenuItem
              key="cableOption"
              onClick={() => {
                selectType(
                  selectedComponentKey,
                  pond.BinComponent.BIN_COMPONENT_GRAIN_CABLE,
                  selectedComponentTopNode
                );
              }}>
              Grain Cable
            </MenuItem>
          );
        }
        if (selectedComponentType === quack.ComponentType.COMPONENT_TYPE_BOOLEAN_OUTPUT) {
          options.push(
            <MenuItem
              key="controlOption"
              onClick={() => {
                if (
                  selectedComponentSubtype === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_HEATER
                ) {
                  selectType(selectedComponentKey, pond.BinComponent.BIN_COMPONENT_HEATER);
                } else if (
                  selectedComponentSubtype ===
                  quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_AERATION_FAN
                ) {
                  selectType(selectedComponentKey, pond.BinComponent.BIN_COMPONENT_FAN);
                }
              }}>
              Heaters & Fans
            </MenuItem>
          );
        }
    
        if (options.length === 0) {
          return <MenuItem>No Available Options</MenuItem>;
        } else {
          return options;
        }
      };

    const assignmentMenu = () => {
        return (
          <Menu
            id="groupMenu"
            anchorEl={anchorEl}
            open={Boolean(anchorEl)}
            onClose={() => setAnchorEl(null)}
            keepMounted
            disableAutoFocusItem>
            {getOptions()}
          </Menu>
        );
    };

    const cableCard = (cable: GrainCable) => {
        const component = cable.asComponent()
        let icon = GetComponentIcon(component.type(), component.subType(), themeType)
        let unit = user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C"
      
        const hasHumidity = cable.aveHumidity() !== 0
        const hasMoisture = cable.grainMoistures.length > 0
      
        const rows: { label: string; min: string; avg: string; max: string }[] = [
          {
            label: `Temp ${unit}`,
            min: cable.minTemp(user.tempUnit(), filterNodes).toFixed(2),
            avg: cable.aveTemp(user.tempUnit(), filterNodes).toFixed(2),
            max: cable.maxTemp(user.tempUnit(), filterNodes).toFixed(2),
          },
          ...(hasHumidity ? [{
            label: "RH %",
            min: cable.minHumidity(filterNodes).toFixed(2),
            avg: cable.aveHumidity(filterNodes).toFixed(2),
            max: cable.maxHumidity(filterNodes).toFixed(2),
          }] : []),
          ...(hasMoisture ? [{
            label: "EMC %",
            min: cable.minMoisture(filterNodes).toFixed(2),
            avg: cable.aveMoisture(filterNodes).toFixed(2),
            max: cable.maxMoisture(filterNodes).toFixed(2),
          }] : []),
        ]
      
        return (
            <BinSensorCard 
                icon={icon} 
                lastReading={cable.lastReading} 
                name={cable.name()} 
                tag={"Cable"}
                cableRows={rows} 
                onMenuClick={(event) => {
                    setComponentUnnassigned(false);
                    setSelectedComponentType(cable.type());
                    setSelectedComponentKey(cable.key());
                    setSelectedComponentTopNode(cable.settings.grainFilledTo);
                    setAnchorEl(event.currentTarget);
                }}/>
        )
    }

    const tempHumidCard = (sensor: Plenum | Ambient | Headspace, showEMC?: boolean) => {
        let icon = GetComponentIcon(sensor.settings.type, sensor.settings.subtype, themeType)
        let prefDisplay = "" 
        switch (preferences?.get(sensor.key())?.type){
            case pond.BinComponent.BIN_COMPONENT_PLENUM:
                prefDisplay = "Plenum"
                break;
            case pond.BinComponent.BIN_COMPONENT_AMBIENT:
                prefDisplay = "Ambient"
                break;
            case pond.BinComponent.BIN_COMPONENT_HEADSPACE:
                prefDisplay = "Headspace"
        }
        
        let rows: {label: string, data: string}[] = [
            // build temperature row data
            {
                label: "Temp " + (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C"),
                data: (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? sensor.temperature * (9 / 5) + 32 : sensor.temperature).toFixed(2)
            },
            // build humidity row
            {
                label: "RH %",
                data: sensor.humidity.toFixed(2)
            }
        ]
        // build moisture row assuming the bin has a grain type to use to calculatee the moisture
        if(showEMC && bin.grain() !== pond.Grain.GRAIN_INVALID && bin.grain() !== pond.Grain.GRAIN_NONE){
            let emc = ExtractMoisture(
                bin.grain(),
                sensor.temperature,
                sensor.humidity,
                bin.customGrain()
            )
            rows.push(
                {
                    label: "EMC %",
                    data: emc.toFixed(2)
                }
            )
        }

        return (
            <BinSensorCard 
                lastReading={sensor.lastReading}
                name={sensor.name()}
                tag={prefDisplay}
                icon={icon}
                rows={rows}
                onMenuClick={(event) => {
                    setComponentUnnassigned(false);
                    setSelectedComponentType(sensor.type());
                    setSelectedComponentKey(sensor.key());
                    setAnchorEl(event.currentTarget);
                }}
            />
        )
    }

    const pressureCard = (pressure: Pressure) => {
        let icon = GetComponentIcon(pressure.settings.type, pressure.settings.subtype, themeType)
        let rows: {label: string, data: string}[] = [
            {
                label: "Pressure " + (user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? "iwg" : "kPa"),
                data: (user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? pressure.pascals/249 : pressure.pascals/1000).toFixed(2)
            }
        ]

        if(pressure.airflow){
            rows.push({
                label: "Airflow CFM",
                data: pressure.airflow.toFixed(2)
            })
        }

        return (
            <BinSensorCard 
                lastReading={pressure.lastReading}
                name={pressure.name()}
                tag={"Pressure"}
                icon={icon}
                rows={rows}
                onMenuClick={(event) => {
                    setComponentUnnassigned(false);
                    setSelectedComponentType(pressure.type());
                    setSelectedComponentKey(pressure.key());
                    setAnchorEl(event.currentTarget);
                }}
            />
        )
    }
    const co2Card = (sensor: CO2) => {
        let icon = GetComponentIcon(sensor.settings.type, sensor.settings.subtype, themeType)
        let rows: {label: string, data: string}[] = [
            {
                label: "CO2 ppm",
                data: sensor.ppm.toFixed(2)
            }
        ]

        return (
            <BinSensorCard 
                lastReading={sensor.lastReading}
                name={sensor.name()}
                tag={"Headspace"}
                icon={icon}
                rows={rows}
                onMenuClick={(event) => {
                    setComponentUnnassigned(false);
                    setSelectedComponentType(sensor.type());
                    setSelectedComponentKey(sensor.key());
                    setAnchorEl(event.currentTarget);
                }}
            />
        )
    }

    const lidarCard = (sensor: Component) => {
        let icon = GetComponentIcon(sensor.settings.type, sensor.settings.subtype, themeType)
        let rows: {label: string, data: string}[] = []
        let lastReading = moment.now().toString()
        sensor.lastMeasurement.forEach(unitMeasurement => {
            let label = ""
            let value = 0
            if(sensor.type() === quack.ComponentType.COMPONENT_TYPE_LIDAR){
                if(unitMeasurement.type === quack.MeasurementType.MEASUREMENT_TYPE_DISTANCE_CM){
                    label = "Lidar " + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? " ft" : " M")
                    if(unitMeasurement.timestamps.length > 0){
                        lastReading = unitMeasurement.timestamps[0]
                    }
                    if (unitMeasurement.values.length > 0){
                        //distance is stored in cm so needs to be converted
                        value = avg(unitMeasurement.values[0].values)
                        value = user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? value/30.48 : value/100
                    }

                }
            }
            rows.push({label: label, data: value.toFixed(2)})
        })

        return (
            <BinSensorCard 
                lastReading={lastReading}
                name={sensor.name()}
                tag={"Headspace"}
                icon={icon}
                rows={rows}
                onMenuClick={(event) => {
                    setComponentUnnassigned(false);
                    setSelectedComponentType(sensor.type());
                    setSelectedComponentKey(sensor.key());
                    setAnchorEl(event.currentTarget);
                }}
            />
            
        )
    }

    const controllerCard = (controller: Controller) => {
        const component = controller.asComponent()
        let icon = GetComponentIcon(component.type(), component.subType(), themeType)
        const isStale = moment().diff(moment(controller.lastReading), "hours") > 6
        const isAuto = controller.mode === quack.OutputMode.OUTPUT_MODE_AUTO
        const isOn = controller.mode === quack.OutputMode.OUTPUT_MODE_ON
        const isOff = controller.mode === quack.OutputMode.OUTPUT_MODE_OFF
    
        const prefType = preferences?.get(controller.key())?.type
        const tag = prefType === pond.BinComponent.BIN_COMPONENT_FAN ? "Fan" : "Heater"
    
        const segStyle = (active: boolean, activeColor?: string): React.CSSProperties => ({
            flex: 1,
            padding: "5px 0",
            fontSize: 11,
            fontWeight: 500,
            textAlign: "center",
            cursor: "pointer",
            borderRadius: 0,
            backgroundColor: active ? (activeColor ?? theme.palette.success.main) : "transparent",
            color: active ? "#fff" : theme.palette.text.secondary,
            border: "none",
            transition: "background-color 0.15s",
        })
    
        return (
            <Card raised sx={{ height: "100%" }}>
                <Box padding={1.5} height="100%" display="flex" flexDirection="column">
    
                    <Box display="flex" justifyContent="space-between" alignItems="center" marginBottom={1}>
                        <Box display="flex" alignItems="center" gap={1}>
                            <Avatar
                                variant="square"
                                src={icon}
                                alt={controller.name() + " icon"}
                                style={{ width: theme.spacing(3), height: theme.spacing(3) }}
                            />
                            <Typography fontWeight={500}>{controller.name()}</Typography>
                            <Typography variant="caption" color="textSecondary">- {tag}</Typography>
                        </Box>
                        <IconButton
                            size="small"
                            onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
                                setComponentUnnassigned(false)
                                setSelectedComponentType(controller.type())
                                setSelectedComponentKey(controller.key())
                                setAnchorEl(event.currentTarget)
                            }}
                        >
                            <MoreVert fontSize="small" />
                        </IconButton>
                    </Box>
    
                    <Box display="flex" justifyContent="space-between" alignItems="center" marginBottom={1.5}>
                        <Typography variant="caption" color="textSecondary">Current state</Typography>
                        <Box display="flex" alignItems="center" gap={0.5}>
                            <Box
                                sx={{
                                    width: 7,
                                    height: 7,
                                    borderRadius: "50%",
                                    backgroundColor: controller.on
                                        ? theme.palette.success.main
                                        : theme.palette.text.disabled,
                                }}
                            />
                            <Typography
                                variant="caption"
                                fontWeight={500}
                                color={controller.on ? "success.main" : "text.secondary"}
                            >
                                {controller.on ? "Running" : isAuto ? "Standby" : "Off"}
                            </Typography>
                        </Box>
                    </Box>
    
                    <Box
                        display="flex"
                        sx={{
                            border: `0.5px solid ${theme.palette.divider}`,
                            borderRadius: 1,
                            overflow: "hidden",
                        }}
                    >
                        {[
                            { label: "Auto", mode: quack.OutputMode.OUTPUT_MODE_AUTO, active: isAuto },
                            { label: "On",   mode: quack.OutputMode.OUTPUT_MODE_ON,   active: isOn },
                            { label: "Off",  mode: quack.OutputMode.OUTPUT_MODE_OFF,  active: isOff },
                        ].map(({ label, mode, active }, i) => (
                            <Box
                                key={label}
                                component="button"
                                onClick={() => {
                                    //this will update the components settings here to change the mode
                                    console.log("changing mode: " + mode)
                                    controller.settings.defaultOutputState = mode
                                    let device = componentDevices.get(controller.key())
                                    if(device){
                                      componentAPI.update(device, controller.settings).then(resp => {
                                        controller.mode = mode  // ← update the field the UI reads
                            
                                        if (prefType === pond.BinComponent.BIN_COMPONENT_FAN) {
                                            setFans(prev => prev.map(f => f.key() === controller.key() ? controller : f))
                                        } else {
                                            setHeaters(prev => prev.map(h => h.key() === controller.key() ? controller : h))
                                        }
                                    }).catch(err => {
                                        console.log("there was a problem updating the controller")
                                    })
                                    }
                                    
                                }}
                                sx={{
                                    ...segStyle(active, label === "Off" ? theme.palette.action.selected : undefined),
                                    borderLeft: i > 0 ? `0.5px solid ${theme.palette.divider}` : "none",
                                }}
                            >
                                {label}
                            </Box>
                        ))}
                    </Box>
    
                    <Box display="flex" alignItems="center" gap={0.5} marginTop="auto" paddingTop={1}>
                        <AccessTime sx={{ fontSize: 12, color: isStale ? "warning.main" : "text.disabled" }} />
                        <Typography variant="caption" color={isStale ? "warning.main" : "text.secondary"}>
                            {moment(controller.lastReading).fromNow()}
                        </Typography>
                    </Box>
    
                </Box>
            </Card>
        )
    }

    const unassignedComponentCard = (component: Component) => {
      let icon = GetComponentIcon(component.type(), component.subType(), themeType)
      const lastReading = component.lastMeasurement.length > 0 
          ? component.lastMeasurement[0].timestamps[0] ?? "" 
          : ""
      const isStale = moment().diff(moment(lastReading), "hours") > 6
  
      return (
          <Card raised sx={{ height: "100%" }}>
              <Box padding={1.5} height="100%" display="flex" flexDirection="column">
                  <Box display="flex" justifyContent="space-between" alignItems="center">
                      <Box display="flex" alignItems="center" gap={1}>
                          <Avatar
                              variant="square"
                              src={icon}
                              alt={component.name() + " icon"}
                              style={{ width: theme.spacing(3), height: theme.spacing(3) }}
                          />
                          <Typography fontWeight={500}>{component.name()}</Typography>
                      </Box>
                      <IconButton
                          size="small"
                          onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
                              setComponentUnnassigned(true)
                              setSelectedComponentType(component.type())
                              setSelectedComponentKey(component.key())
                              setSelectedComponentSubtype(component.subType())
                              setSelectedComponentTopNode(0)
                              setAnchorEl(event.currentTarget)
                          }}
                      >
                          <MoreVert fontSize="small" />
                      </IconButton>
                  </Box>
  
                  <Box display="flex" alignItems="center" gap={0.5} marginTop="auto">
                      <AccessTime sx={{ fontSize: 12, color: isStale ? "warning.main" : "text.disabled" }} />
                      <Typography variant="caption" color={isStale ? "warning.main" : "text.secondary"}>
                          {lastReading ? moment(lastReading).fromNow() : "No readings yet"}
                      </Typography>
                  </Box>
  
              </Box>
          </Card>
      )
  }
    const updateDateRange = (newStartDate: any, newEndDate: any) => {
      let range = GetDefaultDateRange();
      range.start = newStartDate;
      range.end = newEndDate;
      setStartDate(newStartDate);
      setEndDate(newEndDate);
    };

    const graphControls = () => {
        return (
            <Box display="flex" gap={2} alignItems="center">
                <Button variant="contained" color="primary" onClick={() => {
                    setShowGraphs(!showGraphs)
                }}>
                    {showGraphs ? "Show Cards" : "Show Graphs"}
                </Button>
                {showGraphs && !isMobile &&
                    <TimeBar updateDateRange={updateDateRange} startDate={startDate} endDate={endDate} />
                }
                {cables.length > 0 &&
                  <FormControlLabel
                    control={
                      <Checkbox
                        checked={!filterNodes}
                        onChange={(e, checked) => {
                          setFilterNodes(!filterNodes)
                        }}
                      />
                    }
                    label={<Typography>Show All Nodes
                    </Typography>}
                  />
                }
            </Box>
        )
    }

    return (
        <Box padding={1}>
          {assignmentMenu()}
          {sensorCount > 0 &&
            <Box>
                <Box display="flex" gap={2} alignItems="center" marginBottom={1}>
                  <Typography sx={{fontWeight: 650, fontSize: 25}}>Sensors</Typography>
                  {graphControls()}
                </Box>
                {showGraphs && isMobile &&
                    <TimeBar updateDateRange={updateDateRange} startDate={startDate} endDate={endDate} />
                }
                <Grid2 container spacing={2}>
                    {plenums.map(plenum => {
                        let device = componentDevices.get(plenum.key())
                        if(showGraphs && device){
                            let icon = GetComponentIcon(plenum.type(), plenum.subType(), themeType)
                            return(
                                <Grid2 key={plenum.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                    <BinSensorGraph 
                                      icon={icon} 
                                      title={plenum.name()} 
                                      tag={"Plenum"} 
                                      device={device} 
                                      component={components.get(plenum.key())!} 
                                      startDate={startDate} 
                                      endDate={endDate} 
                                      onMenuClick={(event) => {
                                        setComponentUnnassigned(false);
                                        setSelectedComponentType(plenum.type());
                                        setSelectedComponentKey(plenum.key());
                                        setAnchorEl(event.currentTarget);
                                      }}
                                    />
                                </Grid2>
                            )
                        }
                        return(
                            <Grid2 key={plenum.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                {tempHumidCard(plenum)}
                            </Grid2>
                        )
                      }
                    )}
                {pressures.map(pressure => {
                    let device = componentDevices.get(pressure.key())
                    if(showGraphs && device){
                        let icon = GetComponentIcon(pressure.type(), pressure.subType(), themeType)
                        return(
                            <Grid2 key={pressure.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                <BinSensorGraph 
                                  icon={icon} 
                                  title={pressure.name()} 
                                  tag={"Pressure"} 
                                  device={device} 
                                  component={components.get(pressure.key())!} 
                                  startDate={startDate} 
                                  endDate={endDate} 
                                  onMenuClick={(event) => {
                                    setComponentUnnassigned(false);
                                    setSelectedComponentType(pressure.type());
                                    setSelectedComponentKey(pressure.key());
                                    setAnchorEl(event.currentTarget);
                                  }}
                                />
                            </Grid2>
                        )
                    }
                    return(
                        <Grid2 key={pressure.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                            {pressureCard(pressure)}
                        </Grid2>
                    )
                })}
                {ambient.map(ambient => {
                    let device = componentDevices.get(ambient.key())
                    if(showGraphs && device){
                        let icon = GetComponentIcon(ambient.type(), ambient.subType(), themeType)
                        return(
                            <Grid2 key={ambient.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                <BinSensorGraph 
                                  icon={icon} 
                                  title={ambient.name()} 
                                  tag={"Ambient"} 
                                  device={device} 
                                  component={components.get(ambient.key())!} 
                                  startDate={startDate} 
                                  endDate={endDate} 
                                  onMenuClick={(event) => {
                                    setComponentUnnassigned(false);
                                    setSelectedComponentType(ambient.type());
                                    setSelectedComponentKey(ambient.key());
                                    setAnchorEl(event.currentTarget);
                                  }}
                                />
                            </Grid2>
                        )
                    }
                    return(
                        <Grid2 key={ambient.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                            {tempHumidCard(ambient)}
                        </Grid2>
                    )
                  }
                )}
                {headspaceTH.map(h => {
                    let device = componentDevices.get(h.key())
                    if(showGraphs && device){
                        let icon = GetComponentIcon(h.type(), h.subType(), themeType)
                        return(
                            <Grid2 key={h.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                <BinSensorGraph 
                                  icon={icon} 
                                  title={h.name()} 
                                  tag={"Headspace"} 
                                  device={device} 
                                  component={components.get(h.key())!} 
                                  startDate={startDate} 
                                  endDate={endDate} 
                                  onMenuClick={(event) => {
                                    setComponentUnnassigned(false);
                                    setSelectedComponentType(h.type());
                                    setSelectedComponentKey(h.key());
                                    setAnchorEl(event.currentTarget);
                                  }}
                                />
                            </Grid2>
                        )
                    }
                    return(
                      <Grid2 key={h.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                          {tempHumidCard(h)}
                      </Grid2> 
                    )
                })}

                {headspaceCO2.map(co2 => {
                    let device = componentDevices.get(co2.key())
                    if(showGraphs && device){
                        let icon = GetComponentIcon(co2.type(), co2.subType(), themeType)
                        return(
                            <Grid2 key={co2.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                <BinSensorGraph 
                                  icon={icon} 
                                  title={co2.name()} 
                                  tag={"Headspace"} 
                                  device={device} 
                                  component={components.get(co2.key())!} 
                                  startDate={startDate} 
                                  endDate={endDate}
                                  onMenuClick={(event) => {
                                    setComponentUnnassigned(false);
                                    setSelectedComponentType(co2.type());
                                    setSelectedComponentKey(co2.key());
                                    setAnchorEl(event.currentTarget);
                                  }}
                                  />
                            </Grid2>
                        )
                    }
                    return(
                        <Grid2 key={co2.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                            {co2Card(co2)}
                        </Grid2> 
                      )
                })}
                {headspaceLidar.map(lidar => {
                    let device = componentDevices.get(lidar.key())
                    if(showGraphs && device){
                        let icon = GetComponentIcon(lidar.type(), lidar.subType(), themeType)
                        return(
                            <Grid2 key={lidar.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                <BinSensorGraph 
                                icon={icon} 
                                title={lidar.name()} 
                                tag={"Headspace"} 
                                device={device} 
                                component={components.get(lidar.key())!} 
                                startDate={startDate} 
                                endDate={endDate} 
                                onMenuClick={(event) => {
                                  setComponentUnnassigned(false);
                                  setSelectedComponentType(lidar.type());
                                  setSelectedComponentKey(lidar.key());
                                  setAnchorEl(event.currentTarget);
                                }}
                                />
                            </Grid2>
                        )
                    }
                    return (
                        <Grid2 key={lidar.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                            {lidarCard(lidar)}
                        </Grid2>
                    )
                })}
                {cables.map(cable => {
                  let device = componentDevices.get(cable.key())
                  if(showGraphs && device){
                      let icon = GetComponentIcon(cable.type(), cable.subType(), themeType)
                      return(
                          <Grid2 key={cable.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                              <BinSensorGraph 
                                icon={icon} 
                                title={cable.name()} 
                                tag={"Cable Averages"} 
                                device={device} 
                                component={components.get(cable.key())!} 
                                startDate={startDate} 
                                endDate={endDate}
                                allNodes={!filterNodes}
                                onMenuClick={(event) => {
                                  setComponentUnnassigned(false);
                                  setSelectedComponentType(cable.type());
                                  setSelectedComponentKey(cable.key());
                                  setSelectedComponentTopNode(cable.settings.grainFilledTo);
                                  setAnchorEl(event.currentTarget);
                                }}
                              />
                          </Grid2>
                      )
                  }
                  return(
                      <Grid2 key={cable.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                          {cableCard(cable)}
                      </Grid2>
                  )
                })}
                </Grid2>
            </Box>
          }

          {controllerCount > 0 &&
            <Box>
              <Typography sx={{fontWeight: 650, fontSize: 25}}>Controllers</Typography>
              <Grid2 container spacing={2}>
                {heaters.map(heater => {
                  let device = componentDevices.get(heater.key())
                  if(showGraphs && device){
                      let icon = GetComponentIcon(heater.type(), heater.subType(), themeType)
                      return(
                          <Grid2 key={heater.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                              <BinSensorGraph 
                              device={device} 
                              icon={icon}
                              title={heater.name()} 
                              tag={"Heater"} 
                              component={components.get(heater.key())!} 
                              startDate={startDate} 
                              endDate={endDate} 
                              onMenuClick={(event) => {
                                setComponentUnnassigned(false);
                                setSelectedComponentType(heater.type());
                                setSelectedComponentKey(heater.key());
                                setAnchorEl(event.currentTarget);
                              }}
                              />
                          </Grid2>
                      )
                  }
                  return (
                    <Grid2 key={heater.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                        {controllerCard(heater)}
                    </Grid2>
                  )
                })}
                {fans.map(fan => {
                    let device = componentDevices.get(fan.key())
                    if(showGraphs && device){
                      let icon = GetComponentIcon(fan.type(), fan.subType(), themeType)
                        return(
                            <Grid2 key={fan.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                                <BinSensorGraph 
                                  device={device}
                                  icon={icon}
                                  title={fan.name()} 
                                  tag={"Fan"} 
                                  component={components.get(fan.key())!} 
                                  startDate={startDate} 
                                  endDate={endDate} 
                                  onMenuClick={(event) => {
                                    setComponentUnnassigned(false);
                                    setSelectedComponentType(fan.type());
                                    setSelectedComponentKey(fan.key());
                                    setAnchorEl(event.currentTarget);
                                  }}
                                  />
                            </Grid2>
                        )
                    }
                    return (
                        <Grid2 key={fan.key()} size={{xs: 12, sm: 6, md: 4, lg: 3}}>
                            {controllerCard(fan)}
                        </Grid2>
                    )
                  })}
              </Grid2>
            </Box>
          }
          {unassignedComponents.length > 0 &&
              <Box>
                  <Typography sx={{ fontWeight: 650, fontSize: 25 }}>Unassigned Components</Typography>
                  <Grid2 container spacing={2}>
                      {unassignedComponents.map(comp => (
                          <Grid2 key={comp.key()} size={{ xs: 6, sm: 6, md: 4, lg: 3 }}>
                              {unassignedComponentCard(comp)}
                          </Grid2>
                      ))}
                  </Grid2>
              </Box>
          }
        </Box>
    )
}