/**
 * Computes which allocations/resources fall within the multi-select rectangle
 * after the user finishes a right-click drag selection.
 */

import { useEffect } from "react";
import { LABEL_WIDTH } from "~/components/timeline/timelineConstants.js";
import type { MultiSelectState } from "~/hooks/useTimelineDrag.js";
import type {
  TimelineAssignmentEntry,
  TimelineDemandEntry,
  ViewMode,
  ResourceBrief,
} from "~/components/timeline/TimelineContext.js";

interface ProjectGroup {
  id: string;
  resourceRows: {
    resource: { id: string };
    allocs: TimelineAssignmentEntry[];
  }[];
}

export function useMultiSelectIntersection({
  multiSelectState,
  setMultiSelectState,
  clearMultiSelect,
  canvasRef,
  viewMode,
  resources,
  allocsByResource,
  projectGroups,
  openDemandsByProject,
  dates,
  today,
  CELL_WIDTH,
  toLeft,
  toWidth,
}: {
  multiSelectState: MultiSelectState;
  setMultiSelectState: React.Dispatch<React.SetStateAction<MultiSelectState>>;
  clearMultiSelect: () => void;
  canvasRef: React.RefObject<HTMLDivElement | null>;
  viewMode: ViewMode;
  resources: ResourceBrief[];
  allocsByResource: Map<string, TimelineAssignmentEntry[]>;
  projectGroups: ProjectGroup[];
  openDemandsByProject: Map<string, TimelineDemandEntry[]>;
  dates: Date[];
  today: Date;
  CELL_WIDTH: number;
  toLeft: (d: Date) => number;
  toWidth: (s: Date, e: Date) => number;
}) {
  useEffect(() => {
    // Only compute when drag just ended (isSelecting false but has coordinates)
    if (multiSelectState.isSelecting) return;
    if (multiSelectState.startX === 0 && multiSelectState.startY === 0) return;
    if (multiSelectState.selectedAllocationIds.length > 0 || multiSelectState.selectedResourceIds.length > 0) return;

    const canvasEl = canvasRef.current;
    if (!canvasEl) return;

    // Selection rectangle in viewport coordinates
    const selTop = Math.min(multiSelectState.startY, multiSelectState.currentY);
    const selBottom = Math.max(multiSelectState.startY, multiSelectState.currentY);
    const selLeft = Math.min(multiSelectState.startX, multiSelectState.currentX);
    const selRight = Math.max(multiSelectState.startX, multiSelectState.currentX);

    // Convert viewport X to canvas-relative X for allocation matching
    const canvasRect = canvasEl.getBoundingClientRect();
    const canvasXOffset = canvasRect.left + LABEL_WIDTH;
    const toCanvasX = (clientX: number) => clientX - canvasXOffset;

    const selLeftCanvas = toCanvasX(selLeft);
    const selRightCanvas = toCanvasX(selRight);

    // Derive date range from pixel X positions
    const colIndexStart = Math.max(0, Math.min(dates.length - 1, Math.floor(selLeftCanvas / CELL_WIDTH)));
    const colIndexEnd = Math.max(0, Math.min(dates.length - 1, Math.floor(selRightCanvas / CELL_WIDTH)));
    const startDate = dates[colIndexStart] ?? today;
    const endDate = dates[colIndexEnd] ?? today;

    const selectedIds: string[] = [];
    const selectedResIds: string[] = [];

    // Query all rendered row elements (virtualizer only renders visible + overscan rows)
    const rowElements = canvasEl.querySelectorAll<HTMLElement>("[data-index]");

    if (viewMode === "resource") {
      rowElements.forEach((rowEl) => {
        const idx = Number(rowEl.dataset.index);
        const resource = resources[idx];
        if (!resource) return;

        const rowRect = rowEl.getBoundingClientRect();
        if (rowRect.bottom < selTop || rowRect.top > selBottom) return;
        selectedResIds.push(resource.id);

        const allocs = allocsByResource.get(resource.id) ?? [];
        for (const alloc of allocs) {
          const allocLeft = toLeft(new Date(alloc.startDate));
          const allocRight = allocLeft + toWidth(new Date(alloc.startDate), new Date(alloc.endDate));
          if (allocRight >= selLeftCanvas && allocLeft <= selRightCanvas) {
            selectedIds.push(alloc.id);
          }
        }
      });
    } else if (viewMode === "project") {
      const projectRowEls = canvasEl.querySelectorAll<HTMLElement>("[data-project-resource-row]");
      projectRowEls.forEach((rowEl) => {
        const rowRect = rowEl.getBoundingClientRect();
        if (rowRect.bottom < selTop || rowRect.top > selBottom) return;

        const projectId = rowEl.dataset.projectId;
        const resourceId = rowEl.dataset.resourceId;
        if (!projectId || !resourceId) return;

        const group = projectGroups.find((g) => g.id === projectId);
        if (!group) return;
        const row = group.resourceRows.find((r) => r.resource.id === resourceId);
        if (!row) return;

        for (const alloc of row.allocs) {
          const allocLeft = toLeft(new Date(alloc.startDate));
          const allocRight = allocLeft + toWidth(new Date(alloc.startDate), new Date(alloc.endDate));
          if (allocRight >= selLeftCanvas && allocLeft <= selRightCanvas) {
            selectedIds.push(alloc.id);
          }
        }
      });

      // Also check demand rows for open demand selection
      const demandRowEls = canvasEl.querySelectorAll<HTMLElement>("[data-project-demand-row]");
      demandRowEls.forEach((rowEl) => {
        const rowRect = rowEl.getBoundingClientRect();
        if (rowRect.bottom < selTop || rowRect.top > selBottom) return;

        const projectId = rowEl.dataset.projectId;
        if (!projectId) return;

        const demands = openDemandsByProject.get(projectId) ?? [];
        for (const demand of demands) {
          const allocLeft = toLeft(new Date(demand.startDate));
          const allocRight = allocLeft + toWidth(new Date(demand.startDate), new Date(demand.endDate));
          if (allocRight >= selLeftCanvas && allocLeft <= selRightCanvas) {
            selectedIds.push(demand.id);
          }
        }
      });
    }

    if (selectedIds.length > 0 || selectedResIds.length > 0) {
      setMultiSelectState(prev => ({
        ...prev,
        selectedAllocationIds: selectedIds,
        selectedResourceIds: selectedResIds,
        dateRange: { start: startDate, end: endDate },
      }));
    } else {
      clearMultiSelect();
    }
  }, [multiSelectState.isSelecting, multiSelectState.startX, multiSelectState.startY]); // eslint-disable-line react-hooks/exhaustive-deps
}
