import { useCallback, useMemo, useState } from "react";

export type SortDir = "asc" | "desc";

export type Sorter<T> = (a: T, b: T) => number;

/**
 * Small hook for client-side sortable tables. Pass a map of sort-key ->
 * comparator; the hook tracks the active key + direction and returns a sorted
 * copy of the input. Clicking the same key toggles asc/desc; a new key resets
 * to desc (typical "most recent / highest first" default).
 */
export function useSort<T, K extends string>(
  items: T[],
  sorters: Record<K, Sorter<T>>,
  initialKey: K,
  initialDir: SortDir = "desc",
) {
  const [key, setKey] = useState<K>(initialKey);
  const [dir, setDir] = useState<SortDir>(initialDir);

  const toggle = useCallback((next: K) => {
    setKey((prev) => {
      if (prev === next) {
        setDir((d) => (d === "asc" ? "desc" : "asc"));
        return prev;
      }
      setDir("desc");
      return next;
    });
  }, []);

  const sorted = useMemo(() => {
    const cmp = sorters[key];
    if (!cmp) return items;
    const arr = [...items].sort(cmp);
    return dir === "desc" ? arr.reverse() : arr;
  }, [items, sorters, key, dir]);

  return { sorted, key, dir, toggle, setKey, setDir };
}

/** Ascending comparator for a numeric/date field (null/NaN sort last). */
export function byNumber<T>(pick: (v: T) => number | null | undefined): Sorter<T> {
  return (a, b) => {
    const av = pick(a);
    const bv = pick(b);
    const an = av == null || Number.isNaN(av) ? Number.POSITIVE_INFINITY : Number(av);
    const bn = bv == null || Number.isNaN(bv) ? Number.POSITIVE_INFINITY : Number(bv);
    return an - bn;
  };
}

/** Ascending comparator for a string field. */
export function byString<T>(pick: (v: T) => string | null | undefined): Sorter<T> {
  return (a, b) => String(pick(a) ?? "").localeCompare(String(pick(b) ?? ""));
}
