import { Box, Grid2 as Grid, Typography, Theme, Divider } from "@mui/material";
import GrainDescriber from "grain/GrainDescriber";
import { Component } from "models";
import { convertedUnitMeasurement } from "models/UnitMeasurement";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
import React, { useEffect, useState } from "react";
import { Plenum } from "models/Plenum";
import { Pressure } from "models/Pressure";
import { GrainCable } from "models/GrainCable";
import { extension, Summary } from "pbHelpers/ComponentType";
import { makeStyles } from "@mui/styles";

interface Props {
  component: Component | Plenum | Pressure | GrainCable;
  reading?: convertedUnitMeasurement | null;
  tableCell?: boolean;
  centered?: boolean;
  dense?: boolean;
  omitTime?: boolean;
  onlyRecent?: boolean;
  largeText?: boolean;
  boldMeasurements?: boolean;
}

const useStyles = makeStyles((theme: Theme) => {
  return ({
    "@keyframes ripple": {
      from: {
        transform: "scale(.8)",
        opacity: 1
      },
      to: {
        transform: "scale(1.4)",
        opacity: 0
      }
    },
    on: {
      boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
      animationName: "$ripple",
      animationDuration: "1.2s",
      animationTimingFunction: "ease-in-out",
      animationIterationCount: "infinite"
    },
    off: {
      backgroundColor: "transparent"
    },
    divider: {
      margin: theme.spacing(1)
    }
  })
});

export default function UnitMeasurementSummary(props: Props) {
  const {
    component,
    reading,
    tableCell,
    centered,
    dense,
    onlyRecent,
    largeText,
    boldMeasurements
  } = props;
  const [summaries, setSummaries] = useState<Summary[]>([]);
  const [timestamp, setTimestamp] = useState("");
  const [recent, setRecent] = useState(true);
  const classes = useStyles();

  useEffect(() => {
    if (reading) {
      if (onlyRecent) {
        setRecent(
          moment().diff(moment(reading.timestamp), "milliseconds") <=
            component.settings.reportPeriodMs
        );
      }
      setTimestamp(reading.timestamp);
      setSummaries(
        extension(component.type(), component.subType()).unitMeasurementSummary(
          reading
        )
      );
    }
  }, [component, reading]); // eslint-disable-line react-hooks/exhaustive-deps

  const noSummary = () => {
    return (
      <Typography variant="body1" color="textPrimary">
        No Data
      </Typography>
    );
  };

  const noRecent = () => {
    return (
      <Typography variant="body1" color="textPrimary">
        No Recent Data
      </Typography>
    );
  };

  const getSummaryComponent = (summaries: Summary[]): any => {
    if (summaries.length < 1) {
      return noSummary();
    }

    let overlays: JSX.Element[] = [];
    let grain = GrainDescriber(component.settings.grainType);
    return (
      <Grid container>
        <Grid size={{ xs: 12 }}>
          <Typography variant={largeText ? "body1" : "caption"} color="textPrimary">
            {summaries.map((summary: Summary, index: number) => {
              let sumVal = summary.value;
              if (component.settings.hasOverlays) {
                let overlay: pond.ComponentOverlays = pond.ComponentOverlays.create();
                let found = false;
                component.settings.overlays.forEach(ov => {
                  if (ov.measurementType === summary.type) {
                    //check if the sum value is within the overlay min-max, currently only checks based off the first node
                    //TODO-CS: possibly consider having more overlays by checking all nodes
                    let numVal = parseFloat(sumVal);
                    if (numVal >= ov.min && numVal <= ov.max) {
                      overlay = ov;
                      found = true;
                    }
                  }
                });
                if (found) {
                  overlays.push(
                    <React.Fragment key={"overlay" + index}>
                      <Grid >
                        <Box
                          width="20px"
                          height="20px"
                          borderRadius="50%"
                          className={classes.on}
                          style={{ background: overlay.colour }}
                        />
                      </Grid>
                      <Grid >
                        <Typography
                          variant={largeText ? "body1" : "caption"}
                          component="span"
                          style={{ marginLeft: 5, marginRight: 5 }}>
                          {overlay.message}
                        </Typography>
                      </Grid>
                    </React.Fragment>
                  );
                }
              }

              return (
                <span key={index}>
                  {summary.label}
                  {summary.error && <span style={{ color: "red" }}>{" [error(s)]"}</span>}
                  {": "}
                  <span style={{ color: summary.colour, fontWeight: boldMeasurements ? 650 : 500 }}>
                    {sumVal}
                  </span>{" "}
                  <br />
                </span>
              );
            })}
          </Typography>
        </Grid>
        {component.settings.grainType !== pond.Grain.GRAIN_NONE &&
          component.settings.grainType !== pond.Grain.GRAIN_INVALID && (
            <Typography variant={largeText ? "body1" : "caption"} color="textPrimary">
              <span key={"grainType"}>
                Grain Type: <span style={{ color: grain.colour }}>{grain.name}</span>
              </span>
            </Typography>
          )}
        {!props.omitTime && (
          <Grid size={{ xs: 12 }}>
            <Typography color="textSecondary" variant={largeText ? "body1" : "caption"}>
              {moment(timestamp).fromNow()}
            </Typography>
          </Grid>
        )}
        {overlays.length > 0 && (
          <React.Fragment>
            <Grid size={{ xs: 12 }}>
              <Divider variant="middle" className={classes.divider} />
            </Grid>
            <Grid container direction="row">
              {overlays}
            </Grid>
          </React.Fragment>
        )}
      </Grid>
    );
  };

  const getTableCellSummaryComponent = (summaries: Summary[]): any => {
    if (summaries.length < 1 || summaries === undefined) {
      return <span>Unknown</span>;
    }
    const blacklist: Array<any> = [];
    const filteredSummaries = summaries.filter((item: any) => !blacklist.includes(item.label));
    return (
      <Grid container direction="row" justifyContent={centered ? "center" : "flex-start"} spacing={1}>
        {filteredSummaries.map((summary: Summary, i: number) => {
          let sumVal = summary.value;
          return (
            <Grid key={"summary-" + i}>
              {summary.label}
              {summary.error && <span style={{ color: "red" }}>{" [error(s)]"}</span>}
              {": "}
              <span style={{ color: summary.colour, fontWeight: boldMeasurements ? 650 : 500 }}>
                {sumVal}
              </span>{" "}
              {i + 1 !== filteredSummaries.length && ","}
            </Grid>
          );
        })}
      </Grid>
    );
  };

  const getDenseSummary = (summaries: Summary[]): any => {
    if (summaries.length < 1) {
      return null;
    }

    const blacklist: Array<any> = ["Temperature (Air)", "Moisture (Air)"];
    const filteredSummaries = summaries.filter(
      (item: any) =>
        !blacklist.includes(item.label) && (item.label !== "Grain Type" || item.value !== "None")
    );

    let overlays: any = [];

    return (
      <Box width={"100%"} component="div" key={Math.random()}>
        {filteredSummaries.map((summary: Summary, i: number) => {
          let sumVal = summary.value;
          if (component.settings.hasOverlays) {
            let overlay: pond.ComponentOverlays = pond.ComponentOverlays.create();
            let found = false;
            component.settings.overlays.forEach(ov => {
              if (ov.measurementType === summary.type) {
                //check if the sum value is within the overlay min-max
                let numVal = parseFloat(sumVal);
                if (numVal >= ov.min && numVal <= ov.max) {
                  overlay = ov;
                  found = true;
                }
              }
            });
            if (found) {
              overlays.push(
                <React.Fragment key={"overlay" + i}>
                  <Grid >
                    <Box
                      width="20px"
                      height="20px"
                      borderRadius="50%"
                      className={classes.on}
                      style={{ background: overlay.colour }}
                    />
                  </Grid>
                  <Grid >
                    <Typography
                      variant={largeText ? "body1" : "caption"}
                      component="span"
                      style={{ marginLeft: 5, marginRight: 5 }}>
                      {overlay.message}
                    </Typography>
                  </Grid>
                </React.Fragment>
              );
            }
          }
          return (
            <Typography
              key={"summary-" + i}
              variant={largeText ? "body1" : "caption"}
              component="span">
              <span style={{ color: summary.colour }}>{sumVal}</span>
              {i + 1 !== filteredSummaries.length && ", "}
            </Typography>
          );
        })}
        {!props.omitTime && (
          <Box component="span">
            {" - "}
            <Typography color="textSecondary" variant={largeText ? "body1" : "caption"}>
              {moment(timestamp).fromNow()}
            </Typography>
          </Box>
        )}
        <Grid container direction="row">
          {overlays}
        </Grid>
      </Box>
    );
  };

  if (!recent) return noRecent();
  if (summaries.length <= 0) return noSummary();
  if (dense) return getDenseSummary(summaries);
  if (tableCell) return getTableCellSummaryComponent(summaries);
  return getSummaryComponent(summaries);
}
