import { useCallback, useMemo, useRef, useState } from 'react';

/**
 * Multi-select over an ordered list of asset ids.
 *
 * Shift-click selects a range, which is why the hook needs the ORDER of everything currently on screen and not
 * just the set of chosen ids. The order comes from the view, so a timeline that has loaded three months and an
 * album that has loaded one page both get the same behaviour without either knowing how the other paginates.
 */
export function useSelection(orderedIds: string[]) {
  const [selected, setSelected] = useState<ReadonlySet<string>>(new Set());
  const anchor = useRef<string | null>(null);

  const order = useMemo(() => new Map(orderedIds.map((id, i) => [id, i])), [orderedIds]);

  const toggle = useCallback(
    (id: string, ev?: { shiftKey?: boolean; preventDefault?: () => void; stopPropagation?: () => void }) => {
      ev?.preventDefault?.();
      ev?.stopPropagation?.();

      setSelected((prev) => {
        const next = new Set(prev);
        const from = anchor.current;

        if (ev?.shiftKey && from && order.has(from) && order.has(id)) {
          const a = order.get(from) ?? 0;
          const b = order.get(id) ?? 0;
          for (let i = Math.min(a, b); i <= Math.max(a, b); i++) {
            const between = orderedIds[i];
            if (between) next.add(between);
          }
          return next;
        }

        if (next.has(id)) next.delete(id);
        else next.add(id);
        anchor.current = id;
        return next;
      });
    },
    [order, orderedIds],
  );

  const clear = useCallback(() => {
    anchor.current = null;
    setSelected(new Set());
  }, []);

  const selectAll = useCallback(() => setSelected(new Set(orderedIds)), [orderedIds]);

  const ids = useMemo(() => orderedIds.filter((id) => selected.has(id)), [orderedIds, selected]);

  return {
    selected,
    /** In document order, so "add to album" preserves what the eye saw rather than insertion order. */
    ids,
    count: selected.size,
    isSelecting: selected.size > 0,
    toggle,
    clear,
    selectAll,
  };
}

export type Selection = ReturnType<typeof useSelection>;
