import { useEffect, useMemo, useState } from "react";
import type { DateRange as DayPickerDateRange } from "react-day-picker";
import {
  getRangeForPreset,
  parseDateOption,
  rangesEqual,
  toYmd,
  type DateRange,
  type TimeframePreset,
} from "./graphHelpers.ts";

export type DateFilterMode = "preset" | "custom";

type UseGraphDateFilterParams = {
  dateOptions: string[];
};

const toPresetDayPickerRange = (
  dates: string[],
  preset: Exclude<TimeframePreset, "custom">
): DayPickerDateRange | undefined => {
  if (dates.length === 0) return undefined;

  const presetRange = getRangeForPreset(dates, preset);
  const fallbackFrom = parseDateOption(dates[0]);
  const fallbackTo = parseDateOption(dates[dates.length - 1]);

  return {
    from: presetRange.startDate ? parseDateOption(presetRange.startDate) : fallbackFrom,
    to: presetRange.endDate ? parseDateOption(presetRange.endDate) : fallbackTo,
  };
};

export function useGraphDateFilter({ dateOptions }: UseGraphDateFilterParams) {
  const [dateFilterMode, setDateFilterMode] = useState<DateFilterMode>("preset");
  const [selectedPreset, setSelectedPreset] = useState<Exclude<TimeframePreset, "custom">>("all");
  const [customRange, setCustomRange] = useState<DayPickerDateRange | undefined>(undefined);
  const [visibleMonth, setVisibleMonth] = useState<Date | undefined>(undefined);
  const [appliedDateRange, setAppliedDateRange] = useState<DateRange>({});
  const [dateRangeError, setDateRangeError] = useState<string | null>(null);

  const today = useMemo(() => {
    const now = new Date();
    return new Date(now.getFullYear(), now.getMonth(), now.getDate());
  }, []);

  const dataDates = useMemo(() => dateOptions.map(parseDateOption), [dateOptions]);
  const sliderStartDate = customRange?.from ? toYmd(customRange.from) : "";
  const sliderEndDate = (customRange?.to ?? customRange?.from) ? toYmd((customRange?.to ?? customRange?.from) as Date) : "";

  useEffect(() => {
    if (dateOptions.length === 0) {
      setDateRangeError("No test dates available for range filtering");
      setAppliedDateRange({});
      return;
    }

    setDateRangeError(null);

    if (dateFilterMode === "preset") {
      setAppliedDateRange(getRangeForPreset(dateOptions, selectedPreset));
      return;
    }

    const startDate = customRange?.from ? toYmd(customRange.from) : undefined;
    const endDate = customRange?.to ? toYmd(customRange.to) : startDate;

    setAppliedDateRange({ startDate, endDate });
  }, [
    dateOptions,
    dateFilterMode,
    selectedPreset,
    customRange,
  ]);

  useEffect(() => {
    if (dateOptions.length > 0) {
      const firstDate = parseDateOption(dateOptions[0]);
      const lastDate = parseDateOption(dateOptions[dateOptions.length - 1]);
      setCustomRange({
        from: firstDate,
        to: lastDate,
      });
      setVisibleMonth(lastDate);
      return;
    }

    setCustomRange(undefined);
    setVisibleMonth(undefined);
  }, [dateOptions]);

  useEffect(() => {
    if (dateFilterMode !== "preset" || dateOptions.length === 0) return;

    const nextRange = toPresetDayPickerRange(dateOptions, selectedPreset);
    if (!nextRange) return;

    setCustomRange((previous) =>
      rangesEqual(previous, nextRange) ? previous : nextRange
    );
  }, [dateFilterMode, selectedPreset, dateOptions]);

  useEffect(() => {
    const anchor = customRange?.to ?? customRange?.from;
    if (!anchor) return;
    setVisibleMonth(anchor);
  }, [customRange?.from?.getTime(), customRange?.to?.getTime()]);

  const clearDateRange = () => {
    if (dateOptions.length > 0) {
      setCustomRange({
        from: parseDateOption(dateOptions[0]),
        to: parseDateOption(dateOptions[dateOptions.length - 1]),
      });
    } else {
      setCustomRange(undefined);
    }

    setDateFilterMode("preset");
    setSelectedPreset("all");
    setDateRangeError(null);
    setAppliedDateRange({});
  };

  const applyTimeframePreset = (preset: Exclude<TimeframePreset, "custom">) => {
    setDateFilterMode("preset");
    setSelectedPreset(preset);

    const nextRange = toPresetDayPickerRange(dateOptions, preset);
    if (!nextRange) return;

    setCustomRange(nextRange);
    setVisibleMonth(nextRange.to ?? nextRange.from);
  };

  const handleCustomRangeChange = (range: DayPickerDateRange | undefined) => {
    setCustomRange((previous) => {
      if (rangesEqual(previous, range)) {
        return previous;
      }

      setDateFilterMode("custom");
      return range;
    });
  };

  return {
    dateFilterMode,
    setDateFilterMode,
    selectedPreset,
    setSelectedPreset,
    sliderStartDate,
    sliderEndDate,
    appliedDateRange,
    dateRangeError,
    clearDateRange,
    applyTimeframePreset,
    customRange,
    handleCustomRangeChange,
    dataDates,
    today,
    visibleMonth,
    setVisibleMonth,
  };
}