import { useTheme } from "@mui/material";
import { blue, indigo, orange, red } from "@mui/material/colors";
import MaterialChartTooltip from "charts/MaterialChartTooltip";
import { usePrevious } from "hooks";
import moment from "moment";
import { useEffect, useState } from "react";
import {
  Area,
  AreaChart,
  Legend,
  ReferenceArea,
  ResponsiveContainer,
  Tooltip,
  TooltipProps,
  XAxis,
  YAxis
} from "recharts";
import { roundTo } from "utils/numbers";

export interface GrainDryingPoint {
  timestamp: number;
  dryScore: number;
}

interface Props {
  data: GrainDryingPoint[];
  showStroke?: boolean;
  useGradient?: boolean;
  displayY?: boolean;
  newXDomain?: number[] | string[];
  multiGraphZoom?: (domain: number[] | string[]) => void;
  multiGraphZoomOut?: boolean;
}

export default function GrainDryingChart(props: Props) {
  const { data, showStroke, useGradient, displayY, newXDomain, multiGraphZoom } = props;
  const prevData = usePrevious(data);
  const theme = useTheme();
  const [offset, setOffset] = useState(0);
  const now = moment();
  const veryDry = red[800];
  const dry = orange[500];
  const damp = blue[500];
  const veryDamp = indigo[800];
  const [xDomain, setXDomain] = useState<string[] | number[]>(["dataMin", "dataMax"]);
  const [refLeft, setRefLeft] = useState<number | undefined>();
  const [refRight, setRefRight] = useState<number | undefined>();

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

  useEffect(() => {
    const gradientOffset = () => {
      const vpdMax = Math.max(...data.map(p => p.dryScore));
      const vpdMin = Math.min(...data.map(p => p.dryScore));

      if (vpdMax <= 0) {
        return 0;
      }
      if (vpdMin >= 0) {
        return 1;
      }

      return vpdMax / (vpdMax - vpdMin);
    };

    if (!prevData || prevData !== data) {
      setOffset(gradientOffset());
    }
  }, [data, prevData, now]);

  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);
      }
    }
  };

  //just commenting this out as this charts zoom will likely never be controlled from inside
  // const zoomOut = () => {
  //   setXDomain(["dataMin", "dataMax"]);
  // };

  if (data.length <= 1) return null;
  return (
    <ResponsiveContainer width={"100%"} height={270}>
      <AreaChart
        data={data}
        onMouseDown={(e: any) => {
          if (e) {
            setRefLeft(e.activeLabel);
          }
        }}
        onMouseMove={(e: any) => {
          if (e) {
            setRefRight(e.activeLabel);
          }
        }}
        onMouseUp={() => {
          setRefLeft(undefined);
          setRefRight(undefined);
          zoom();
        }}>
        {displayY && (
          <YAxis
            tickFormatter={vpd => {
              let val = vpd.toFixed(2);
              return val;
            }}
            type="number"
            // label={{
            //   value: "Water Content",
            //   angle: -90,
            //   position: "insideLeft",
            //   fill: theme.palette.text.primary
            // }}
            domain={["auto", "auto"]}
            tick={{ fill: theme.palette.text.primary }}
          />
        )}
        <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"
        />
        <Legend
          verticalAlign="top"
          payload={[
            { value: "Drying", type: "square", id: "drying", color: orange[800] },
            { value: "Hydrating", type: "square", id: "hydrating", color: blue[800] }
          ]}
        />
        <Tooltip
          animationEasing="ease-out"
          cursor={{ fill: theme.palette.text.primary, opacity: "0.15" }}
          labelFormatter={timestamp => moment(timestamp).format("lll")}
          content={(props: TooltipProps<any, any>) => (
            <MaterialChartTooltip
              {...props}
              valueFormatter={score =>
                `${roundTo(parseFloat(String(score)), 2).toString()} ${
                  score === 0 ? "" : score as number > 0 ? " (Drying)" : " (Hydrating)"
                }`
              }
            />
          )}
        />
        <defs>
          <linearGradient id="gradientColour" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={veryDry} stopOpacity="90%" />
            <stop offset={offset} stopColor={dry} stopOpacity="75%" />
            <stop offset={offset} stopColor={damp} stopOpacity="75%" />
            <stop offset="100%" stopColor={veryDamp} stopOpacity="90%" />
          </linearGradient>
          <linearGradient id="solidColour" x1="0" y1="0" x2="0" y2="1">
            <stop offset={offset} stopColor={dry} stopOpacity="75%" />
            <stop offset={offset} stopColor={damp} stopOpacity="75%" />
          </linearGradient>
        </defs>
        <Area
          type="monotone"
          dataKey={"dryScore"}
          name="Score"
          stroke={
            showStroke
              ? useGradient
                ? "url(#gradientColour)"
                : "url(#solidColour)"
              : "transparent"
          }
          strokeWidth={3}
          fill={useGradient ? "url(#gradientColour)" : "url(#solidColour)"}
        />
        {refLeft && refRight ? (
          <ReferenceArea x1={refLeft} x2={refRight} strokeOpacity={0.3} />
        ) : null}
      </AreaChart>
    </ResponsiveContainer>
  );
}
