import { FC, useEffect, useId, useLayoutEffect, useState } from "react";
import { Alert, Skeleton, Box, LoadingOverlay } from "@mantine/core";
import { IconAlertTriangle, IconInfoCircle } from "@tabler/icons-react";
import {
  InstantQueryResult,
  RangeSamples,
} from "../../api/responseTypes/query";
import { useAPIQuery } from "../../api/api";
import classes from "./Graph.module.css";
import { GraphDisplayMode } from "../../state/queryPageSlice";
import { formatSeries } from "../../lib/formatSeries";
import uPlot, { Series } from "uplot";
import UplotReact from "uplot-react";
import "uplot/dist/uPlot.min.css";
import "./uplot.css";
import { useElementSize } from "@mantine/hooks";
import { formatTimestamp } from "../../lib/formatTime";
import { computePosition, shift, flip, offset, Axis } from "@floating-ui/dom";
import { colorPool } from "./ColorPool";
import UPlotChart, { UPlotChartProps, UPlotChartRange } from "./UPlotChart";

export interface GraphProps {
  expr: string;
  endTime: number | null;
  range: number;
  resolution: number | null;
  showExemplars: boolean;
  displayMode: GraphDisplayMode;
  retriggerIdx: number;
  onSelectRange: (start: number, end: number) => void;
}

const Graph: FC<GraphProps> = ({
  expr,
  endTime,
  range,
  resolution,
  showExemplars,
  displayMode,
  retriggerIdx,
  onSelectRange,
}) => {
  const { ref, width } = useElementSize();
  const [rerender, setRerender] = useState(true);

  const effectiveEndTime = (endTime !== null ? endTime : Date.now()) / 1000;
  const startTime = effectiveEndTime - range / 1000;
  const effectiveResolution =
    resolution || Math.max(Math.floor(range / 250000), 1);

  const { data, error, isFetching, isLoading, refetch } =
    useAPIQuery<InstantQueryResult>({
      key: useId(),
      path: "/query_range",
      params: {
        query: expr,
        step: effectiveResolution.toString(),
        start: startTime.toString(),
        end: effectiveEndTime.toString(),
      },
      enabled: expr !== "",
    });

  // Keep the displayed chart range separate from the actual query range, so that
  // the chart will keep displaying the old range while a new query for a different range
  // is still in progress.
  const [displayedChartRange, setDisplayedChartRange] =
    useState<UPlotChartRange>({
      startTime: startTime,
      endTime: effectiveEndTime,
      resolution: effectiveResolution,
    });

  useEffect(() => {
    setDisplayedChartRange({
      startTime: startTime,
      endTime: effectiveEndTime,
      resolution: effectiveResolution,
    });
  }, [data]);

  useEffect(() => {
    expr !== "" && refetch();
  }, [retriggerIdx, refetch, expr, endTime, range, resolution]);

  useEffect(() => {
    if (data !== undefined && rerender) {
      setRerender(false);
    }
  }, [data, rerender, setRerender]);

  // TODO: Share all the loading/error/empty data notices with the DataTable.

  // Show a skeleton only on the first load, not on subsequent ones.
  if (isLoading) {
    return (
      <Box>
        {Array.from(Array(5), (_, i) => (
          <Skeleton key={i} height={30} mb={15} />
        ))}
      </Box>
    );
  }

  if (error) {
    return (
      <Alert
        color="red"
        title="Error executing query"
        icon={<IconAlertTriangle size={14} />}
      >
        {error.message}
      </Alert>
    );
  }

  if (data === undefined) {
    return <Alert variant="transparent">No data queried yet</Alert>;
  }

  const { result, resultType } = data.data;

  if (resultType !== "matrix") {
    return (
      <Alert
        title="Invalid query result"
        icon={<IconAlertTriangle size={14} />}
      >
        This query returned a result of type "{resultType}", but a matrix was
        expected.
      </Alert>
    );
  }

  if (result.length === 0) {
    return (
      <Alert title="Empty query result" icon={<IconInfoCircle size={14} />}>
        This query returned no data.
      </Alert>
    );
  }

  return (
    <Box pos="relative" ref={ref} className={classes.chartWrapper}>
      <LoadingOverlay
        visible={isFetching}
        zIndex={1000}
        h={570}
        overlayProps={{ radius: "sm", blur: 0.5 }}
        loaderProps={{ type: "dots", color: "gray" }}
        // loaderProps={{
        //   children: <Skeleton m={0} w="100%" h="100%" />,
        // }}
        // styles={{ loader: { width: "100%", height: "100%" } }}
      />
      <UPlotChart
        data={data.data.result}
        range={displayedChartRange}
        width={width}
        showExemplars={showExemplars}
        displayMode={displayMode}
        onSelectRange={onSelectRange}
      />
    </Box>
  );
};

export default Graph;
