"use client";

import { clsx } from "clsx";
import { useMemo } from "react";
import { addDays, createDatePositionCache } from "~/components/timeline/utils.js";
import { formatMonthYear } from "~/lib/format.js";

export function useTimelineLayout(
  viewStart: Date,
  viewDays: number,
  zoom: "day" | "week" | "month",
  showWeekends: boolean,
  today: Date,
) {
  const CELL_WIDTH = zoom === "day" ? 40 : zoom === "week" ? 14 : 4;

  // Visible dates, filtered by showWeekends
  const dates = useMemo(() => {
    const result: Date[] = [];
    for (let i = 0; i < viewDays; i++) {
      const d = addDays(viewStart, i);
      if (!showWeekends && (d.getDay() === 0 || d.getDay() === 6)) continue;
      result.push(d);
    }
    return result;
  }, [viewStart, viewDays, showWeekends]);

  const visibleDays = dates.length;
  const totalCanvasWidth = visibleDays * CELL_WIDTH;

  // O(1) position helpers via pre-computed cache
  const { toLeft, toWidth } = useMemo(
    () => createDatePositionCache(viewStart, viewDays, CELL_WIDTH, showWeekends),
    [viewStart, viewDays, CELL_WIDTH, showWeekends],
  );

  // Grid lines — memoized; identical for every row
  const gridLines = useMemo(() => dates.map((date, i) => {
    const isToday = date.toDateString() === today.toDateString();
    const isSaturday = date.getDay() === 6;
    const isSunday = date.getDay() === 0;
    return (
      <div
        key={i}
        className={clsx(
          "absolute top-0 bottom-0 border-r",
          isToday ? "border-brand-300 dark:border-brand-700 border-r-2" :
          isSaturday ? "border-amber-200 dark:border-amber-800 bg-amber-50/40 dark:bg-amber-950/20" :
          isSunday ? "border-gray-200 dark:border-gray-700 bg-gray-100/60 dark:bg-gray-800/40" :
          "border-gray-100 dark:border-gray-800",
        )}
        style={{ left: i * CELL_WIDTH, width: CELL_WIDTH }}
      />
    );
  }), [dates, CELL_WIDTH, today]); // eslint-disable-line react-hooks/exhaustive-deps

  // Month groups for the month header
  const monthGroups = useMemo(() => {
    const groups: { label: string; colCount: number }[] = [];
    for (const d of dates) {
      const label = formatMonthYear(d);
      const last = groups[groups.length - 1];
      if (last && last.label === label) last.colCount++;
      else groups.push({ label, colCount: 1 });
    }
    return groups;
  }, [dates]);

  // Convert clientX to a Date on the visible timeline
  function xToDate(clientX: number, rowCanvasRect: DOMRect): Date {
    const x = clientX - rowCanvasRect.left;
    const colIndex = Math.max(0, Math.min(dates.length - 1, Math.floor(x / CELL_WIDTH)));
    return dates[colIndex] ?? today;
  }

  return { CELL_WIDTH, dates, visibleDays, totalCanvasWidth, toLeft, toWidth, gridLines, monthGroups, xToDate };
}
