import { Box, MenuItem, TextField } from "@mui/material";
import TrendingChart, { DataPoint, TrendPoint } from "charts/TrendingChart";
import { ExtractMoisture } from "grain";
import { Bin } from "models";
import { GrainCable } from "models/GrainCable";
import { Plenum } from "models/Plenum";
import { UnitMeasurement } from "models/UnitMeasurement";
import moment from "moment";
import { quack } from "protobuf-ts/quack";
import { useEffect, useState } from "react";

interface Props {
  bin: Bin;
  plenums: Plenum[];
  cables: GrainCable[];
  measurementMap: Map<string, UnitMeasurement[]>;
  returnLastMeasurements: (
    dataPoint: DataPoint | undefined,
    trendPoint: TrendPoint | undefined
  ) => void;
  newXDomain?: number[] | string[];
  multiGraphZoom?: (domain: number[] | string[]) => void;
  multiGraphZoomOut?: boolean;
}

export default function BinGraphsTrending(props: Props) {
  const {
    bin,
    plenums,
    cables,
    measurementMap,
    newXDomain,
    multiGraphZoom,
    multiGraphZoomOut,
    returnLastMeasurements
  } = props;
  const [plenum, setPlenum] = useState("");
  const [cable, setCable] = useState("");
  const [cableOptions, setCableOptions] = useState<GrainCable[]>([]);
  const [chartData, setChartData] = useState<DataPoint[]>([]);
  const [trendData, setTrendData] = useState<TrendPoint[]>([]);

  useEffect(() => {
    let plenum: string = "";
    if (plenums[0]) {
      plenum = plenums[0].key();
    }
    let ops: GrainCable[] = [];
    let cable: string = "";
    cables.forEach(c => {
      if (c.humidities.length > 0) {
        ops.push(c);
        if (ops.length === 1) {
          cable = c.key();
        }
      }
    });
    setPlenum(plenum);
    setCable(cable);
    setCableOptions(ops);
  }, [plenums, cables]);

  useEffect(() => {
    if (plenum && cable) {
      let lastData: DataPoint | undefined;
      let lastTrend: TrendPoint | undefined;
      setTrendData([]);
      setChartData([]);
      let data: DataPoint[] = [];
      let trendData: TrendPoint[] = [];
      let plenumMeasurements = measurementMap.get(plenum);
      let cableMeasurements = measurementMap.get(cable);
      if (plenumMeasurements && cableMeasurements) {
        // set the data of the plenum run through the emc equation
        let plenumTemp: UnitMeasurement = UnitMeasurement.create();
        let plenumHumidity: UnitMeasurement = UnitMeasurement.create();

        plenumMeasurements.forEach(um => {
          if (um.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) {
            plenumTemp = um;
          }
          if (um.type === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) {
            plenumHumidity = um;
          }
        });

        if (plenumTemp.values.length > 0) {
          plenumTemp.values.forEach((val, i) => {
            if (val.values[0] && plenumHumidity.values[i] && plenumHumidity.values[i].values[0]) {
              let trendPoint: TrendPoint = {
                timestamp: moment(plenumTemp.timestamps[i]).valueOf(),
                trend: ExtractMoisture(
                  bin.grain(),
                  val.values[0],
                  plenumHumidity.values[i].values[0]
                )
              };
              trendData.push(trendPoint);
              if (!lastTrend || lastTrend.timestamp < trendPoint.timestamp) {
                lastTrend = trendPoint;
              }
            }
          });
        }

        let dataPoint: DataPoint;
        //the grain emc mutation must be set on the component to show this graph
        let grainMoisture: UnitMeasurement | undefined;
        cableMeasurements.forEach(um => {
          if (um.type === quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC) {
            grainMoisture = um;
          }
        });

        //set the data for the grain moisture of the graph ONLY if the component was set to have an emc mutation
        if (grainMoisture) {
          grainMoisture.values.forEach((val, i) => {
            dataPoint = {
              timestamp: grainMoisture ? moment(grainMoisture.timestamps[i]).valueOf() : 0,
              moisture: [Math.min(...val.values), Math.max(...val.values)]
            };
            data.push(dataPoint);
            if (!lastData || lastData.timestamp < dataPoint.timestamp) {
              lastData = dataPoint;
            }
          });
        }
        setChartData(data);
        setTrendData(trendData);
        returnLastMeasurements(lastData, lastTrend);
      }
    }
  }, [plenum, cable, measurementMap, bin]); // eslint-disable-line react-hooks/exhaustive-deps

  return (
    <Box>
      {plenums.length > 1 && (
        <TextField
          style={{ marginRight: 15 }}
          label="Plenum"
          variant="outlined"
          select
          id="plenumSelector"
          value={plenum}
          onChange={e => {
            setPlenum(e.target.value as string);
          }}>
          {plenums.map(k => {
            return (
              <MenuItem key={k.key()} value={k.key()}>
                {k.name()}
              </MenuItem>
            );
          })}
        </TextField>
      )}
      {cableOptions.length > 1 && (
        <TextField
          label="Cable"
          variant="outlined"
          select
          id="cableSelector"
          value={cable}
          onChange={e => {
            setCable(e.target.value as string);
          }}>
          {cableOptions.map(k => {
            return (
              <MenuItem key={k.key()} value={k.key()}>
                {k.name()}
              </MenuItem>
            );
          })}
        </TextField>
      )}
      {trendData.length > 0 && chartData.length > 0 && (
        <TrendingChart
          data={chartData}
          trend={trendData}
          newXDomain={newXDomain}
          multiGraphZoom={multiGraphZoom}
          multiGraphZoomOut={multiGraphZoomOut}
        />
      )}
    </Box>
  );
}
