import { Box, Checkbox, FormControl, MenuItem, List, ListItem, InputLabel, Select, Typography, Stack, FormControlLabel, useTheme } from "@mui/material";
import Bin3dView from "bin/3dView/Scene/Bin3dView";
import { Bin, Component, Device } from "models";
import { Controller } from "models/Controller";
import { pond, quack } from "protobuf-ts/pond";
import React, { useEffect } from "react";
import { useState } from "react";
import NodeControls from "./binSummary/components/nodeControls";
import { NodeData } from "bin/3dView/Data/BuildNodeData";
import { CableData } from "bin/3dView/Data/BuildCableData";
import ModeChangeDialog from "bin/conditioning/modeChangeDialog";
import { cloneDeep } from "lodash";
import { useMobile } from "hooks";

interface Props {
    bin: Bin
    // cables?: GrainCable[]
    devices: Device[]
    // fans?: Controller[]
    // heaters?: Controller[]
    permissions: pond.Permission[]
    componentDevices: Map<string, number>
    componentMap: Map<string, Component>
    binPrefs?: Map<string, pond.BinComponentPreferences>
    updateBinCallback?: (bin: Bin) => void
}
export default function bin3dVisualizer(props: Props){
    const {bin, permissions, devices, componentDevices, componentMap, binPrefs, updateBinCallback} = props
    const theme = useTheme()
    const [showHeatmap, setShowHeatmap] = useState(true)
    // const [showHotspots, setShowHotspots] = useState(false)
    // const [showFill, setShowFill] = useState(false)
    const [showTemp, setShowTemp] = useState(true)
    const [showMoisture, setShowMoisture] = useState(false)
    const [showMoistureHeatmap, setShowMoistureHeatmap] = useState(false)
    const [binDisplay, setBinDisplay] = useState<string>("temp")
    const [binMode, setBinMode] = useState<pond.BinMode>(pond.BinMode.BIN_MODE_NONE)
    const [openModeChange, setOpenModeChange] = useState(false)
    const [selectedCable, setSelectedCable] = useState<CableData | undefined>(undefined)
    const [selectedNode, setSelectedNode] = useState<NodeData | undefined>(undefined)
    const [selectedCableDevice, setSelectedCableDevice] = useState(Device.create()) //this is the device that the cable that has the node that was clicked on belongs to 
    const [filteredComponents, setFilteredComponents] = useState<Component[]>([]) //components that are filtered to only include ones on the same device 
    const [openNodeControls, setOpenNodeControls] = useState(false)
    const [devMap, setDevMap] = useState<Map<number, Device>>(new Map())
    const [modeChangeInProgress, setModeChangeInProgress] = useState(false)
    const [showLabels, setShowLabels] = useState(true)
    const isMobile = useMobile()

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

    useEffect(()=>{
      setBinMode(bin.settings.mode)
    },[bin])

    const updateBin = () => {
      if(updateBinCallback){
        let clone = cloneDeep(bin)
        clone.settings.mode = binMode
        updateBinCallback(clone)
      }
    };

    const binModeControl = () => {
      return (
        <Box>
            <Typography sx={{fontWeight: 650, fontSize: isMobile ? 13 : 17}}>{bin.name()}</Typography>
            <FormControl fullWidth>
              <Select
                value={binMode}
                disabled={modeChangeInProgress}
                sx={{
                  borderRadius: 1,
                  bgcolor: '#151E27',
                  '& .MuiSelect-select': {
                      py: isMobile ? 0.5 : 1.5,
                      fontSize: 13
                  },
                  '& .MuiOutlinedInput-notchedOutline': { border: 'none' },
                  '&:hover .MuiOutlinedInput-notchedOutline': { border: 'none' },
                  '&.Mui-focused .MuiOutlinedInput-notchedOutline': { border: 'none' },
                }}
                onChange={event => {
                  setBinMode(event.target.value as pond.BinMode)
                  setOpenModeChange(true)
                }}
              >
                <MenuItem value={pond.BinMode.BIN_MODE_NONE}>Select Mode..</MenuItem>
                <MenuItem value={pond.BinMode.BIN_MODE_STORAGE}>Storage</MenuItem>
                <MenuItem value={pond.BinMode.BIN_MODE_DRYING}>Drying</MenuItem>
                <MenuItem value={pond.BinMode.BIN_MODE_HYDRATING}>Hydrating</MenuItem>
                <MenuItem value={pond.BinMode.BIN_MODE_COOLDOWN}>Cooldown</MenuItem>
              </Select>
            </FormControl>
        </Box>
      )
    }

    const heatmapDisplay = () => {
      return (
        <Box>
          <Typography noWrap sx={{fontWeight: 650, fontSize: isMobile ? 13 : 17}}>
            Heatmap
          </Typography>
          <FormControl fullWidth>
            <Select
              value={binDisplay}
              sx={{
                borderRadius: 1,
                bgcolor: '#151E27',
                '& .MuiSelect-select': {
                  py: isMobile ? 0.5 : 1.5,
                  fontSize: 13
                },
                '& .MuiOutlinedInput-notchedOutline': { border: 'none' },
                '&:hover .MuiOutlinedInput-notchedOutline': { border: 'none' },
                '&.Mui-focused .MuiOutlinedInput-notchedOutline': { border: 'none' },
              }}
              onChange={event => {
                let selection = event.target.value
                setBinDisplay(selection)
                if (selection === "temp") {
                  setShowHeatmap(true)
                  setShowTemp(true)
                  setShowMoisture(false)
                  setShowMoistureHeatmap(false)
                }
                if (selection === "moisture") {
                  setShowHeatmap(false)
                  setShowTemp(false)
                  setShowMoisture(true)
                  setShowMoistureHeatmap(true)
                }
              }}
            >
              <MenuItem value={"temp"}>Temperature</MenuItem>
              <MenuItem value={"moisture"}>Moisture</MenuItem>
            </Select>
          </FormControl>
          {/* Checkbox moved below dropdown — no longer affects top alignment */}
          <FormControlLabel
            control={
              <Checkbox
                size="small"
                checked={showLabels}
                onChange={(e, checked) => setShowLabels(checked)}
              />
            }
            label={<Typography noWrap sx={{fontSize: 11}}>Show Values</Typography>}
            sx={{ mt: 0.5, ml: '-9px' }}
          />
        </Box>
      )
    }

    // const controllerState = (controller: Controller) => {
    //     let state = false
    //     controller.status.lastGoodMeasurement.forEach(um => {
    //       if(um.type === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN){
    //         if(um.values.length > 0){
    //           let readings = um.values
    //           if(readings[readings.length-1].values.length > 0){
    //             let nodes = readings[readings.length-1].values
    //             if (nodes[nodes.length -1] === 1){
    //               state = true
    //             }
    //           }
    //         }
    //       }
    //     })
    //     return state
    // }

    const controllerDisplay = () => {
      if ((bin.status.fans && bin.status.fans.length > 0) || (bin.status.heaters && bin.status.heaters.length > 0)){
      return (
        <Box width="100%">
          <Typography sx={{fontWeight: 650, fontSize: isMobile ? 13 : 17}}>
            Controllers
          </Typography>
            {bin.status.fans && bin.status.fans.map(fan => {
              // let isOn = controllerState(fan)

              return (
                <Box
                  key={fan.key}
                  sx={{
                      display: 'flex',
                      justifyContent: 'space-between',
                      alignItems: 'center',
                      // bgcolor: 'rgba(255,255,255,0.05)',
                      bgcolor: '#151E27',
                      borderRadius: 1,
                      px: 2,
                      py: 1,
                  }}
              >
                  <Typography sx={{fontSize: 13}}>{fan.name}</Typography>
                  <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
                      <Typography sx={{fontWeight: 650, fontSize: 13}}>
                          {fan.state ? "ON" : "OFF"}
                      </Typography>
                      <Box sx={{
                          width: 8,
                          height: 8,
                          borderRadius: '50%',
                          bgcolor: fan.state ? 'success.main' : 'error.main'
                      }} />
                  </Box>
              </Box>
            )})}
            {bin.status.heaters && bin.status.heaters.map(heater => {
              // let isOn = controllerState(heater)
              return (
                <Box
                  key={heater.key}
                  sx={{
                      display: 'flex',
                      justifyContent: 'space-between',
                      alignItems: 'center',
                      // bgcolor: 'rgba(255,255,255,0.05)',
                      bgcolor: '#151E27',
                      borderRadius: 1,
                      px: 2,
                      py: 1,
                  }}
              >
                  <Typography sx={{fontSize: 13}}>{heater.name}</Typography>
                  <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
                      <Typography sx={{fontWeight: 650, fontSize: 13}}>
                          {heater.state ? "ON" : "OFF"}
                      </Typography>
                      <Box sx={{
                          width: 8,
                          height: 8,
                          borderRadius: '50%',
                          bgcolor: heater.state ? 'success.main' : 'error.main'
                      }} />
                  </Box>
              </Box>
            )})}
        </Box>
        // loop through controllers displaying each one
        
      )
      }else{
        return
      }
    }

    const desktopHUD = () => {
      return (
        <Box position={"absolute"} top={20} left={25} height={"75%"} width={"25%"}>
          <Stack direction={"column"} justifyContent={"space-between"} sx={{height: "100%", width: "100%"}}>
            {binModeControl()}
            {heatmapDisplay()}
            {controllerDisplay()}
          </Stack>
        </Box>
      )
    }

    const mobileHUD = () => {
      return (
        <React.Fragment>
          {/* Top-left: Bin Name / Mode */}
          <Box
            position="absolute"
            top={12}
            left={12}
            width="40%"
            sx={{ pointerEvents: 'none' }}
          >
            <Box sx={{ pointerEvents: 'auto' }}>
              {binModeControl()}
            </Box>
          </Box>
    
          {/* Top-right: Heatmap Display */}
          <Box
            position="absolute"
            top={12}
            right={12}
            width="40%"
            sx={{ pointerEvents: 'none' }}
          >
            <Box sx={{ pointerEvents: 'auto' }}>
              {heatmapDisplay()}
            </Box>
          </Box>
    
          {/* Bottom-left: Controller Status */}
          <Box
            position="absolute"
            bottom={12}
            left={12}
            width="45%"
            sx={{ pointerEvents: 'none' }}
          >
            <Box sx={{ pointerEvents: 'auto' }}>
              {controllerDisplay()}
            </Box>
          </Box>
        </React.Fragment>
      )
    }

    return (
      <React.Fragment>
        {(selectedCable && selectedNode) &&
          <NodeControls 
            bin={bin}
            cable={selectedCable}
            node={selectedNode}
            open={openNodeControls}
            permissions={permissions}
            device={selectedCableDevice}
            filteredComponents={filteredComponents}
            componentMap={componentMap}
            onClose={() => {
              setOpenNodeControls(false)
            }}
          />
        }
        <ModeChangeDialog 
          binKey={bin.key()}
          binMode={binMode}
          grain={bin.settings.inventory?.grainType}
          devices={devices}
          open={openModeChange}
          compDevMap={componentDevices}
          preferences={binPrefs}
          onClose={(refresh) => {
            setOpenModeChange(false)
            if(refresh) {
              updateBin()
            }else{
              setBinMode(bin.settings.mode)
            };
          }}
          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 position={"relative"} height={600}>
          <Bin3dView 
            height={isMobile ? 600 : undefined}
            width={isMobile ? window.innerWidth : undefined}
            bin={bin}
            fillPercent={bin.fillPercent()/100}//expects a decimal between 0 and 1
            nodeClick={(node, cable) => {
              //this will be how to control the dialog to update the top nodes and node exclusion etc (make new component called NodeControls for this)
              //use the cable data to get the device it belongs to
              let d = devMap.get(cable.grainCable.device)
              if(d !== undefined){
                setSelectedNode(node)
                setSelectedCable(cable)
                setSelectedCableDevice(d)
                //filter the controls so that only components on THIS device are options for new interactions, a side note of this using the components that are in the bins status 
                //is that it will indirectly also filter by bin as well so only components that are both on the bin and the same device as the cable will appear
                let filtered: Component[] = []
                if(bin.status.fans){
                  bin.status.fans.forEach((f) => {
                    if(componentDevices.get(f.key) === d.id()){
                      let comp = componentMap.get(f.key)
                      if(comp){
                        filtered.push(comp)
                      }
                    }
                  })
                }
                if(bin.status.heaters){
                  bin.status.heaters.forEach((h) => {
                    if(componentDevices.get(h.key) === d.id()){
                      let comp = componentMap.get(h.key)
                      if(comp){
                        filtered.push(comp)
                      }
                    }
                  })
                }
                //also make sure to push the cable into the list of filtered components for the source
                let c = componentMap.get(cable.grainCable.key)
                if(c !== undefined){
                  filtered.push(c)
                }
                setFilteredComponents(filtered)
                setOpenNodeControls(true)
              }
            }}
            scale={100} 
            showTempHeatmap={showHeatmap}
            showMoistureHeatmap={showMoistureHeatmap}
            showTemp={showTemp && showLabels}
            showMoisture={showMoisture && showLabels}
            xOffset={isMobile ? undefined : -120}
          />
          {isMobile ? mobileHUD() : desktopHUD()}
        </Box>
      </React.Fragment>
    )
}