import { 
  Box, 
  Button, 
  useTheme 
} from "@mui/material";
import MaterialChartTooltip from "charts/MaterialChartTooltip";
import moment from "moment";
import { MeasurementDescriber } from "pbHelpers/MeasurementDescriber";
import { useGlobalState } from "providers";
import { useEffect, useState } from "react";
import {
  AreaChart,
  Area,
  XAxis,
  ResponsiveContainer,
  YAxis,
  Tooltip,
  TooltipProps,
  ReferenceArea
} from "recharts";
import { roundTo } from "utils";

export interface AreaData {
  timestamp: number;
  value: [number, number];
}

interface Props {
  data: AreaData[];
  averagedData?: AreaData[];
  describer: MeasurementDescriber;
  interactionLines?: JSX.Element[];
  overlays?: JSX.Element[];
  yMin?: number | string;
  yMax?: number | string;
  tooltip?: boolean;
  newXDomain?: number[] | string[];
  multiGraphZoom?: (domain: number[] | string[]) => void;
  multiGraphZoomOut?: boolean;
  customHeight?: string | number;
}

export default function AreaGraph(props: Props) {
  const {
    data,
    describer,
    interactionLines,
    overlays,
    yMin,
    yMax,
    tooltip,
    newXDomain,
    multiGraphZoom,
    multiGraphZoomOut,
    customHeight,
    averagedData
  } = props;
  const theme = useTheme();
  const now = moment();
  const [refLeft, setRefLeft] = useState<number | undefined>();
  const [refRight, setRefRight] = useState<number | undefined>();
  const [xDomain, setXDomain] = useState<string[] | number[]>(["dataMin", "dataMax"]);
  // const [{ newStructure }] = useGlobalState();
  const [displayData, setDisplayData] = useState<any[]>([]);

  useEffect(() => {
    if (newXDomain) {
      setXDomain(newXDomain);
    }
  }, [newXDomain]);

  useEffect(() => {
    let d: any[] = [];
    if (data) {
      data.forEach(areaData => {
        let pointSet: any = {
          timestamp: areaData.timestamp
        };
        pointSet[describer.label()] = areaData.value;
        d.push(pointSet);
      });
    }
    if (averagedData) {
      averagedData.forEach(areaData => {
        let pointSet: any = {
          timestamp: areaData.timestamp
        };
        pointSet[describer.label() + "(avg)"] = areaData.value;
        d.push(pointSet);
      });
    }
    setDisplayData(d);
  }, [data, averagedData, describer]);

  const zoom = () => {
    let newDomain: number[] | string[] = ["dataMin", "dataMax"];
    if (refLeft && refRight && refLeft !== refRight) {
      refLeft < refRight ? (newDomain = [refLeft, refRight]) : (newDomain = [refRight, refLeft]);
      setRefLeft(undefined);
      setRefRight(undefined);
      if (multiGraphZoom) {
        multiGraphZoom(newDomain);
      } else {
        setXDomain(newDomain);
      }
    }
  };

  const zoomOut = () => {
    setXDomain(["dataMin", "dataMax"]);
  };

  return (
    <Box>
      {!multiGraphZoomOut && (
        <Button variant="outlined" onClick={zoomOut}>
          Zoom Out
        </Button>
      )}
      <ResponsiveContainer width={"100%"} height={customHeight ?? 350}>
        <AreaChart
          data={displayData}
          onMouseDown={(e: any) => {
            if (e) {
              setRefLeft(e.activeLabel);
            }
          }}
          onMouseMove={(e: any) => {
            if (e) {
              setRefRight(e.activeLabel);
            }
          }}
          onMouseUp={() => {
            setRefLeft(undefined);
            setRefRight(undefined);
            zoom();
          }}>
          <YAxis
            domain={[yMin || yMin === 0 ? yMin : "auto", yMax || yMax === 0 ? yMax : "auto"]}
            label={{
              value: describer.label() + " (" + describer.unit() + ")",
              position: "insideLeft",
              angle: -90,
              fill: theme.palette.text.primary
            }}
            tick={{ fill: theme.palette.text.primary }}
            allowDataOverflow
          />
          {tooltip && (
            <Tooltip
              animationEasing="ease-out"
              cursor={{ fill: theme.palette.text.primary, opacity: "0.15" }}
              labelFormatter={timestamp => moment(timestamp).format("lll")}
              content={(props: TooltipProps<any, any>) => {
                return (
                  <MaterialChartTooltip
                    {...props}
                    valueFormatter={value => {
                      let str = "";
                      if (Array.isArray(value)) {
                        str = value[0].toFixed(1) + ", " + value[1].toFixed(1);
                      } else {
                        str = describer.convertWithoutUnits(
                          roundTo(parseFloat(String(value)), 2),
                          true
                        );
                      }
                      return str + describer.GetUnit();
                    }}
                  />
                );
              }}
            />
          )}
          <XAxis
            allowDataOverflow
            dataKey="timestamp"
            domain={xDomain}
            name="Time"
            tickFormatter={timestamp => {
              let t = moment(timestamp);
              return now.isSame(t, "day") ? t.format("LT") : t.format("MMM DD");
            }}
            scale="time"
            type="number"
            tick={{ fill: theme.palette.text.primary }}
            stroke={theme.palette.divider}
            interval="preserveStartEnd"
          />
          <Area
            dataKey={describer.label()}
            fill={describer.colour() + "75"}
            stroke={describer.colour()}
            strokeWidth={3}
            type="monotone"
          />
          <Area
            dataKey={describer.label() + "(avg)"}
            fill={"white"}
            stroke={"white"}
            strokeWidth={3}
            type="monotone"
          />
          {refLeft && refRight ? (
            <ReferenceArea x1={refLeft} x2={refRight} strokeOpacity={0.3} />
          ) : null}
          {interactionLines}
          {overlays}
        </AreaChart>
      </ResponsiveContainer>
    </Box>
  );
}
