import {
  Box,
  Button,
  Card,
  CardHeader,
  CircularProgress,
  Grid2 as Grid,
  LinearProgress,
  Typography
} from "@mui/material";
import { teal } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import SingleSetAreaChart, { SSAreaDataPoint } from "charts/SingleSetAreaChart";
import { Gate } from "models/Gate";
import moment, { Moment } from "moment";
import { pond } from "protobuf-ts/pond";
import { useGateAPI, useGlobalState } from "providers";
import React, { useEffect, useState } from "react";

interface Props {
  gate: Gate;
  device: string | number;
  start: Moment;
  end: Moment;
  ambient?: string;
  newXDomain?: number[] | string[];
  pressureComponent?: string;
  setPCAState: (state: boolean) => void;
  multiGraphZoom?: (domain: number[] | string[]) => void;
}

const useStyles = makeStyles(() => ({
    calcCard: {
      height: 100,
      display: "flex",
      alignItems: "center"
    },
    eventCard: {
      height: 100,
      paddingX: 10,
      display: "flex",
      alignItems: "center"
    },
    runtimeGrid: {
      marginBottom: 2
    },
    eventGrid: {
      marginTop: 2
    }
}));

export default function GateFlowGraph(props: Props) {
  const {
    gate,
    device,
    ambient,
    pressureComponent,
    setPCAState,
    start,
    end,
    newXDomain,
    multiGraphZoom
  } = props;
  const [{as}] = useGlobalState();
  const gateAPI = useGateAPI();
  const [flowData, setFlowData] = useState<SSAreaDataPoint[]>([]);
  const [loadingChartData, setLoadingChartData] = useState(false);
  const [recent, setRecent] = useState<SSAreaDataPoint | undefined>();
  const [runtime, setRuntime] = useState<moment.Duration>();
  const classes = useStyles();
  const [flowEvents, setFlowEvents] = useState<pond.AirFlowEvent[]>([]);
  const [eventsLoading, setEventsLoading] = useState(false);
  const eventThreshold = 5;
  const idleFlow = 2.44;

  useEffect(() => {
    if (loadingChartData) return;
    if (ambient && pressureComponent) {
      let recent: SSAreaDataPoint | undefined;
      setLoadingChartData(true);
      gateAPI
        .listGateAirflow(
          gate.key,
          device,
          ambient,
          pressureComponent,
          start.toISOString(),
          end.toISOString(),
          undefined,
          undefined,
          as
        )
        .then(resp => {
          let data: SSAreaDataPoint[] = [];
          if (resp.data.values) {
            let start: Moment | undefined;
            let stop: Moment | undefined;
            let runtime = 0;
            resp.data.values.forEach((val, i) => {
              let time = moment(val.time);
              let newPoint: SSAreaDataPoint = {
                timestamp: time.valueOf(),
                value: val.airFlow ?? 0
              };

              data.push(newPoint);
              if (!recent || recent.timestamp < newPoint.timestamp) {
                recent = newPoint;
              }

              /** determine runtime */
              // set the start time if the values is greater than the idleFlow and start is not already set
              if (val.airFlow >= idleFlow && !start) {
                start = time;
              }
              // set the stop time when off or at the last measurements and the start time is set
              if ((val.airFlow < idleFlow || i === resp.data.values.length - idleFlow) && start) {
                stop = time;
              }
              // if both start and stop are set calculate add the timeframe to the total runtime
              if (start && stop) {
                runtime = runtime + stop.diff(start);
                start = undefined;
                stop = undefined;
              }
            });
            setRuntime(moment.duration(runtime));
            let state = false;
            if (
              data.length > 1 &&
              data[data.length - 1].value > gate.lowerFlow() &&
              data[data.length - 1].value < gate.upperFlow()
            ) {
              state = true;
            }
            setPCAState(state);
          }
          setFlowData(data);
          setLoadingChartData(false);
          setRecent(recent);
        });
    }
  }, [gateAPI, gate, ambient, pressureComponent, start, end, device, setPCAState, as]); // eslint-disable-line react-hooks/exhaustive-deps

  const loadFlowEvents = () => {
    if (ambient && pressureComponent) {
      setEventsLoading(true);
      gateAPI
        .listGateFlowEvents(
          gate.key,
          device,
          ambient,
          pressureComponent,
          start.toISOString(),
          end.toISOString(),
          idleFlow,
          eventThreshold,
          undefined,
          undefined,
          as
        )
        .then(resp => {
          console.log(resp);
          setFlowEvents(resp.data.events.map(e => pond.AirFlowEvent.fromObject(e)));
        })
        .catch(err => {})
        .finally(() => {
          setEventsLoading(false);
        });
    }
  };

  const flowChart = () => {
    return (
      <Card raised style={{ padding: 10, marginBottom: 15 }}>
        <CardHeader
          title={<Typography style={{ fontSize: 25, fontWeight: 650 }}>Mass Air Flow</Typography>}
          subheader={
            recent ? (
              <Grid container>
                <Grid size={12}>
                  <span>
                    {"Mass Flow Rate: "}
                    <span style={{ color: teal[500], fontWeight: 500 }}>
                      {recent.value.toFixed(2)} kg/s
                    </span>
                    <br />
                  </span>
                </Grid>
                <Grid size={12}>
                  <Typography color="textSecondary" variant={"caption"}>
                    {moment(recent.timestamp).fromNow()}
                  </Typography>
                </Grid>
              </Grid>
            ) : (
              <Typography variant="body1" color="textPrimary">
                No Data
              </Typography>
            )
          }
        />
        {flowData.length !== 0 ? (
          <SingleSetAreaChart
            data={flowData}
            maxRef={gate.upperFlow()}
            minRef={gate.lowerFlow()}
            newXDomain={newXDomain}
            multiGraphZoom={multiGraphZoom}
          />
        ) : (
          <Box display="flex" flexDirection="column" flexGrow="2">
            <div style={{ display: "flex", flexGrow: 2 }}></div>
            <Typography variant="subtitle1" color="textSecondary" align="center">
              A component may be missing or have no measurements, this data needs the ambient and
              pressure components to be set and measuring
            </Typography>
            <div style={{ display: "flex", flexGrow: 2 }}></div>
          </Box>
        )}
      </Card>
    );
  };

  const eventCards = () => {
    let totalEvents = 0;
    let eventsInside = 0;
    let eventsOutside = 0;
    let totalTimeS = 0;
    let timeSInside = 0;
    let timeSOutside = 0;

    flowEvents.forEach(event => {
      totalEvents++;
      totalTimeS =
        totalTimeS + moment.duration(moment(event.start).diff(moment(event.end))).asSeconds();

      let avg = 0;
      let count = 0;
      event.readings.forEach(reading => {
        avg = avg + reading.airFlow;
        count++;
      });
      avg = avg / count;
      //if the average of the readings for an event are within the range
      if (avg < gate.upperFlow() && avg > gate.lowerFlow()) {
        eventsInside++;
        timeSInside =
          timeSInside + moment.duration(moment(event.start).diff(moment(event.end))).asSeconds();
      } else {
        eventsOutside++;
        timeSOutside =
          timeSOutside + moment.duration(moment(event.start).diff(moment(event.end))).asSeconds();
      }
    });

    return (
      <React.Fragment>
        {flowEvents.length > 0 ? (
          <Grid container direction="row" spacing={2} className={classes.eventGrid}>
            <Grid size={3}>
              <Card raised className={classes.eventCard}>
                <Grid container alignItems="center">
                  <Grid size={9}>
                    <Box display="flex" justifyContent="space-between">
                      <Typography>Total Events:</Typography>
                      <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                        {totalEvents}
                      </Typography>
                    </Box>
                  </Grid>
                  <Grid size={9}>
                    <Box display="flex" justifyContent="space-between">
                      <Typography>Total Time:</Typography>
                      <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                        {moment.duration(totalTimeS, "s").humanize()}
                      </Typography>
                    </Box>
                  </Grid>
                </Grid>
              </Card>
            </Grid>
            <Grid size={3}>
              <Card raised className={classes.eventCard}>
                <Grid container alignItems="center">
                  <Grid size={9}>
                    <Box display="flex" justifyContent="space-between">
                      <Typography>Events Inside:</Typography>
                      <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                        {eventsInside}
                      </Typography>
                    </Box>
                  </Grid>
                  <Grid size={9}>
                    <Box display="flex" justifyContent="space-between">
                      <Typography>Event Time:</Typography>
                      <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                        {moment.duration(timeSInside, "s").humanize()}
                      </Typography>
                    </Box>
                  </Grid>
                </Grid>
              </Card>
            </Grid>
            <Grid size={3}>
              <Card raised className={classes.eventCard}>
                <Grid container alignItems="center">
                  <Grid size={9}>
                    <Box display="flex" justifyContent="space-between">
                      <Typography>Events Outside:</Typography>
                      <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                        {eventsOutside}
                      </Typography>
                    </Box>
                  </Grid>
                  <Grid size={9}>
                    <Box display="flex" justifyContent="space-between">
                      <Typography>Event Time:</Typography>
                      <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                        {moment.duration(timeSOutside, "s").humanize()}
                      </Typography>
                    </Box>
                  </Grid>
                </Grid>
              </Card>
            </Grid>
            <Grid size={3}>
              <Card raised className={classes.eventCard}>
                <Grid container direction="column" alignItems="center">
                  <Grid>
                    <Typography>Performance:</Typography>
                  </Grid>
                  <Grid>
                    <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                      {(eventsInside / totalEvents) * 100}%
                    </Typography>
                  </Grid>
                </Grid>
              </Card>
            </Grid>
          </Grid>
        ) : (
          <Box>
            {eventsLoading ? (
              <Box display="flex" justifyContent="center">
                <CircularProgress size={100} />
              </Box>
            ) : (
              <Box display="flex" justifyContent="center">
                <Button
                  variant="contained"
                  color="primary"
                  onClick={() => {
                    loadFlowEvents();
                  }}>
                  Retrieve Flow Events
                </Button>
              </Box>
            )}
          </Box>
        )}
      </React.Fragment>
    );
  };

  return (
    <React.Fragment>
      {runtime && (
        <Grid container direction="row" spacing={2} className={classes.runtimeGrid}>
          <Grid size={3}>
            <Card raised className={classes.calcCard}>
              <Grid container direction="column" alignItems="center">
                <Grid>Approximate Runtime:</Grid>
                <Grid>
                  <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                    {runtime.asHours().toFixed(2)} hr
                  </Typography>
                </Grid>
              </Grid>
            </Card>
          </Grid>
          <Grid size={3}>
            <Card raised className={classes.calcCard}>
              <Grid container direction="column" alignItems="center">
                <Grid>Cost to run PCA:</Grid>
                <Grid>
                  <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                    $
                    {parseFloat(
                      (runtime.asHours() * gate.settings.hourlyPcaCost).toFixed(2)
                    ).toLocaleString()}
                  </Typography>
                </Grid>
              </Grid>
            </Card>
          </Grid>
          <Grid size={3}>
            <Card raised className={classes.calcCard}>
              <Grid container direction="column" alignItems="center">
                <Grid>Cost to run APU:</Grid>
                <Grid>
                  <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                    $
                    {parseFloat(
                      (runtime.asHours() * gate.settings.hourlyApuCost).toFixed(2)
                    ).toLocaleString()}
                  </Typography>
                </Grid>
              </Grid>
            </Card>
          </Grid>
          <Grid size={3}>
            <Card raised className={classes.calcCard}>
              <Grid container direction="column" alignItems="center">
                <Grid>Total Cost:</Grid>
                <Grid>
                  <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                    $
                    {parseFloat(
                      (
                        runtime.asHours() * gate.settings.hourlyApuCost +
                        runtime.asHours() * gate.settings.hourlyPcaCost
                      ).toFixed(2)
                    ).toLocaleString()}
                  </Typography>
                </Grid>
                <Grid>Estimated Savings:</Grid>
                <Grid>
                  <Typography style={{ fontWeight: 650, fontSize: 15 }}>
                    $
                    {parseFloat(
                      (runtime.asHours() * gate.settings.hourlyApuCost).toFixed(2)
                    ).toLocaleString()}
                  </Typography>
                </Grid>
              </Grid>
            </Card>
          </Grid>
        </Grid>
      )}
      {loadingChartData ? <LinearProgress /> : flowChart()}
      {eventCards()}
    </React.Fragment>
  );
}
