import { Gate } from "models/Gate";
import { Box, Card, IconButton, List, ListItem, ListItemText, Theme, Tooltip, Typography } from "@mui/material";
import React, { useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useMobile } from "hooks";
//import MaterialTable from "material-table";
//import { getTableIcons } from "common/ResponsiveTable";
import { Terminal } from "models/Terminal";
import { makeStyles } from "@mui/styles";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
import AddGateFab from "./AddGateFab";
import GateSettings from "./GateSettings";
import { useGateAPI, useGlobalState } from "providers";
import { CheckCircleOutline, DoNotDisturb, ErrorOutline, HelpOutlineOutlined, Settings } from "@mui/icons-material";
import { cloneDeep } from "lodash";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
import { UnitMeasurement } from "models/UnitMeasurement";
import { quack } from "protobuf-ts/quack";
import { getTemperatureUnit } from "utils";
import { teal } from "@mui/material/colors";
import { react } from "@babel/types";
import { getDeviceStateHelper } from "pbHelpers/DeviceState";

interface Props {
  //gates: Gate[];
  terminals: Terminal[];
  currentTerminal?: string; //the key of the terminal for the currently selected tab
  useMobile: boolean;
  //duplicateGate: (gate: Gate) => void;
}

const useStyles = makeStyles((theme: Theme) => ({
    gridListTile: {
      minHeight: "184px",
      height: "auto !important",
      width: "184px",
      padding: 2
    },
    hidden: {
      visibility: "hidden"
    },
    gateCard: {
      marginBottom: 10,
      paddingLeft: 15
    },
    cellContainer: {
      margin: theme.spacing(1),
      marginLeft: theme.spacing(2),
      display: "flex",
      width: theme.spacing(10)
    }
  }));

export default function GateList(props: Props) {
  const {terminals, currentTerminal } = props;
  const [{as}] = useGlobalState();
  // const history = useHistory();
  const navigate = useNavigate();
  const isMobile = useMobile();
  const classes = useStyles();
  const [{user}] = useGlobalState()
  const [gateDialog, setGateDialog] = useState(false);
  const [tablePage, setTablePage] = useState(0)
  const [pageSize, setPageSize] = useState(10)
  const [total, setTotal] = useState(0)
  const [terminalMap, setTerminalMap] = useState<Map<string, string>>(new Map<string, string>());
  const gateAPI = useGateAPI();
  const [gates, setGates] = useState<Gate[]>([])
  const [selectedGate, setSelectedGate] = useState<Gate | undefined>()
  const [search, setSearch] = useState("")

  const goToGate = (gate: Gate) => {
    let path = "/terminals/" + gate.key;
    navigate(path, { state: gate })
  };

  useEffect(() => {
    let map = new Map<string, string>();
    terminals.forEach(t => {
      map.set(t.key, t.name);
    });
    setTerminalMap(map);
  }, [terminals]);

  const loadGates = useCallback(() => {
    let keys = undefined
    let types = undefined
    if(currentTerminal) {
      keys = [currentTerminal]
      types = ["terminal"]
    }
    gateAPI.listGates(pageSize, pageSize * tablePage, "asc", "name", search, undefined, keys, types, undefined, undefined, as).then(resp => {
      setGates(resp.data.gates.map(gate => Gate.create(gate)))
      setTotal(resp.data.total)
    })
  },[currentTerminal, search, pageSize, tablePage, as])

  useEffect(() => {
    loadGates()
  },[loadGates])

  const handleChange = (event: any) => {
    setPageSize(event.target.value);
  };

  const displayPCAStatus = (state: pond.PCAState) => {
    switch(state){
      case pond.PCAState.PCA_STATE_IN_BOUNDS:
        return (
          <Box display="flex">
            <CheckCircleOutline sx={{color: "green"}}/>
            <Typography paddingLeft={2}>PCA in threshold</Typography>
          </Box>
        )
      case pond.PCAState.PCA_STATE_OUT_BOUNDS:
        return (
          <Box display="flex">
            <ErrorOutline sx={{color: "red"}} />
            <Typography paddingLeft={2}>PCA out of threshold</Typography>
          </Box>
        )
      case pond.PCAState.PCA_STATE_OFF:
        return (
          <Box display="flex">
            <DoNotDisturb />
            <Typography paddingLeft={2}>PCA off</Typography>
          </Box>
        )
      default:
        return (
          <Box display="flex">
            <HelpOutlineOutlined />
            <Typography paddingLeft={2}>PCA device not found</Typography>
          </Box>
        )
    }
  }

  // const lastOutletReading = (reading: pond.UnitMeasurementsForComponent[]) => {
  //   let outletDisplay = "--"
  //   let timeSince = "No Reading Yet"
  //   let color = ""
  //   reading.forEach(um => {
  //     let clone = cloneDeep(um)
  //     let measurement = UnitMeasurement.create(clone, user)
  //     if(measurement.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE || measurement.type === quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE){
  //       let nodes = measurement.values[measurement.values.length-1].values
  //       outletDisplay = nodes[nodes.length-1].toFixed(2) + " " + measurement.unit
  //       timeSince = moment(measurement.timestamps[measurement.timestamps.length-1]).fromNow()
  //       color = measurement.colour
  //     }
  //   })

  //   if(isMobile){
  //     return (
  //       <React.Fragment>
  //           <Typography color={color}>{outletDisplay}</Typography>
  //           <Typography>{timeSince}</Typography>
  //       </React.Fragment>
  //   )
  //   }
  //   return (
  //       <Box padding={2}>
  //         <Box display="flex" justifyContent="space-between">
  //           <Typography>Value:</Typography>
  //           <Typography color={color}>{outletDisplay}</Typography>
  //         </Box>
  //         <Box display="flex" justifyContent="space-between">
  //           <Typography>Time:</Typography>
  //           <Typography>{timeSince}</Typography>
  //         </Box>
  //       </Box>
  //   )
  // }

  // const tempDisplay = (gate: Gate) => {
  //   let display = "--"
  //   if(gate.status.pcaState !== pond.PCAState.PCA_STATE_OFF){
  //     //only display it if the final temp is between -4 and 60 C, is a valid number, and is not exactly 0
  //     //0 is technically a valid number but the likely hood of the calculation being exactly 0 is negligible
  //     if (gate.status.finalTemp < 60 && gate.status.finalTemp > -40 && !isNaN(gate.status.finalTemp) && gate.status.finalTemp !== 0){
  //       display = getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? CtoF(gate.status.finalTemp).toFixed(2) + "°F" : gate.status.finalTemp.toFixed(2) + "°C"
  //     }
  //   }
  //   return (
  //     <Typography>
  //       {display}
  //     </Typography>
  //   )
  // }

  const conditionDisplay = (gate: Gate) => {
    let display = ""
    if(gate.status.pcaState === pond.PCAState.PCA_STATE_OFF){
      display = "PCA Off"
    } else if (gate.status.pcaState === pond.PCAState.PCA_STATE_UNKNOWN){
      display = "--"
    } else { //the pca is currently active calulate the delta temp (outlet - ambient)
      let ambient = cloneDeep(gate.status.lastAmbientReading)
      let temp = cloneDeep(gate.status.lastTempReading)

      if(ambient.length > 0 && temp.length > 0){
        let ambientTemp: number | undefined
        let outletTemp: number | undefined
        ambient.forEach(um => {
          if(um.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE){
            let clone = cloneDeep(um)
            let measurement = UnitMeasurement.any(clone, user)
            if(measurement.values.length > 0){
              let readings = measurement.values[measurement.values.length -1]
              if(readings.values.length > 0){
                ambientTemp = readings.values[readings.values.length -1]
              }
            }
          }
        })
        temp.forEach(um => {
          if(um.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE){
            let clone = cloneDeep(um)
            let measurement = UnitMeasurement.any(clone, user)
            if(measurement.values.length > 0){
              let readings = measurement.values[measurement.values.length -1]
              if(readings.values.length > 0){
                outletTemp = readings.values[readings.values.length -1]
              }
            }
          }
        })
        if(ambientTemp && outletTemp){
          let deltaTemp = outletTemp - ambientTemp
          display = deltaTemp.toFixed(2) + (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C")
        }else{
          display = "Sensor Missing"
        }
      }
    }
    return (
      <Typography>
      {display}
      </Typography>
    )
  }

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

  const desktopCols = (): Column<Gate>[] => {
    return [
      {
        title: "Gate",
        render: gate => (
          <Box padding={2}>
            <Typography>
              {gate.name}
            </Typography>
          </Box>
        )
      },
      {
        title: "Terminal",
        render: gate => (
          <Box padding={2}>
            <Typography>
            {terminalMap.get(gate.terminal())}
            </Typography>
          </Box>
        )
      },
      {
        title: "Device State",
        // cellStyle: {width: 100000},
        // sortKey: "state",
        render: gate => {
          const deviceStateHelper = getDeviceStateHelper(gate.status.pcaDeviceState);
          return (
            <Box className={classes.cellContainer}>
              <Tooltip title={deviceStateHelper.description}>{deviceStateHelper.icon}</Tooltip>
            </Box>
          )
        }
      },
      {
        title: "PCA Status",
        render: gate => {
        return (<Box padding={2}>
            {displayPCAStatus(gate.status.pcaState)}
          </Box>)
        }
      },
      {
        title: "Delta Temperature",
        render: gate => {
          return (
          <Box padding={2}>
            {conditionDisplay(gate)}
          </Box>
        )}
      },
      //taking out these columns for now because were not sure if the customer actually wants them
      // {
      //   title: "Estimated Temp",
      //   render: gate => {
      //     return (
      //       <Box padding={2}>
      //         {tempDisplay(gate)}
      //       </Box>
      //     )
      //   }
      // },
      // {
      //   title: "Last FLow",
      //   render: gate => (
      //     <Box padding={2}>
      //       <Box display="flex" justifyContent="space-between">
      //         <Typography>Flow:</Typography>
      //         <Typography color={teal[500]}>{gate.status.lastMassAirflow.toFixed(2)} kg/s</Typography>
      //       </Box>
      //       <Box display="flex" justifyContent="space-between">
      //         <Typography>Read:</Typography>
      //         <Typography>{gate.status.lastUpdate !== "" ? moment(gate.status.lastUpdate).fromNow() : "No Reading Yet"}</Typography>
      //       </Box>
      //     </Box>
      //   )
      // },
      // {
      //   title: "Outlet Temperature",
      //   render: gate => (
      //     <Box>{lastOutletReading(gate.status.lastTempReading)}</Box>
      //   )
      // },
      // {
      //   title: "Outlet Pressure",
      //   render: gate => (
      //     <Box>{lastOutletReading(gate.status.lastPressureReading)}</Box>
      //   )
      // }
    ]
  }
  const mobileCols = (): Column<Gate>[] => {
    return [{
      title: "",
      render: gate => {
        return (
          <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
            <Typography margin="auto" marginLeft={0} fontWeight={650} fontSize={20}>
              {gate.name}
            </Typography>
            <Box display="flex" alignItems="center" gap={1}>
              {displayPCAStatus(gate.status.pcaState)}
              <IconButton onClick={(event) => {
                event.stopPropagation()
                setSelectedGate(gate)
                setGateDialog(true)
              }}>
                <Settings />
              </IconButton>
            </Box>
          </Box>
        )
      }
    }]
  }

  const gutter = (gate: Gate) => {
    const deviceStateHelper = getDeviceStateHelper(gate.status.pcaDeviceState)
    return(
      <Box>
        <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
          <Typography>Terminal:</Typography>
          <Typography>{terminalMap.get(gate.terminal()) ?? "None"}</Typography>
        </Box>
        <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
          <Typography>Delta Temperature:</Typography>
          {conditionDisplay(gate)}
        </Box>
        <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
          <Typography>Device State:</Typography>
          <Box>
            {deviceStateHelper.icon}
          </Box>
        </Box>
        {/* taking these out for now because we are not sure if the customer wants them */}
        {/* <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
          <Typography>Estimated Temp:</Typography>
          {tempDisplay(gate)}
        </Box>
        <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
          <Typography>Last Flow:</Typography>
          <Typography color={teal[500]}>{gate.status.lastMassAirflow.toFixed(2)} kg/s</Typography>
          <Typography>{gate.status.lastUpdate !== "" ? moment(gate.status.lastUpdate).fromNow() : "No PCA reading yet"}</Typography>
        </Box>
        <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
          <Typography>Outlet Temp:</Typography>
          {lastOutletReading(gate.status.lastTempReading)}
        </Box>
          <Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
          <Typography>Outlet Pressure:</Typography>
          {lastOutletReading(gate.status.lastPressureReading)}
        </Box> */}
      </Box>
    )
  }

  const gateTable = () => {
    return (
      <ResponsiveTable<Gate>
        page={tablePage}
        pageSize={pageSize}
        columns={isMobile || props.useMobile ? mobileCols() : desktopCols()}
        handleRowsPerPageChange={handleChange}
        renderGutter={isMobile || props.useMobile ? gutter : undefined}
        gutterPadding={0}
        rows={gates}
        setPage={(page) => {setTablePage(page)}}
        total={total}
        onRowClick={(gate) => {goToGate(gate)}}
        hideKeys={isMobile || props.useMobile}
        setSearchText={(search) => setSearch(search)}
        loadMore={()=>{
          let current = cloneDeep(gates)
          let keys = undefined
          let types = undefined
          if(currentTerminal) {
            keys = [currentTerminal]
            types = ["terminal"]
          }
          gateAPI.listGates(pageSize, current.length , "asc", "name", search, undefined, keys, types, undefined, undefined, as).then(resp => {
            let newGates = resp.data.gates.map(gate => Gate.create(gate))
            setGates(current.concat(newGates))
          })
        }}
      />
    )
  };

  return <Box>
      <GateSettings
        open={gateDialog}
        gate={selectedGate}
        close={newGate => {
          if (newGate) {
            gates.push(newGate)
          }
          setGateDialog(false);
        }}
        terminals={terminals}
      />
      <AddGateFab
        onClick={() => {
          setGateDialog(true);
        }}
        pulse={gates.length < 1}
      />
      {gateTable()}
  </Box>
}
