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

export interface SortableColumnDef {
  key: string;
  sortType?: 'string' | 'number' | 'date';
  render?: (row: unknown) => unknown;
}

function cellValue(row: unknown, col: SortableColumnDef): unknown {
  if (col.render) return col.render(row);
  if (row && typeof row === 'object') return (row as Record<string, unknown>)[col.key];
  return undefined;
}

function compareValues(
  a: unknown,
  b: unknown,
  sortType: 'string' | 'number' | 'date',
  locale: string,
): number {
  if (a == null && b == null) return 0;
  if (a == null) return 1;
  if (b == null) return -1;
  if (sortType === 'number') {
    return Number(a) - Number(b);
  }
  if (sortType === 'date') {
    return new Date(String(a)).getTime() - new Date(String(b)).getTime();
  }
  return String(a).localeCompare(String(b), locale, { numeric: true });
}

export function sortRows<T>(
  rows: T[],
  columns: SortableColumnDef[],
  sortBy: string | null | undefined,
  sortDir: SortDir | null | undefined,
  locale: string,
): T[] {
  if (!sortBy || !sortDir) return rows;
  const col = columns.find((c) => c.key === sortBy);
  if (!col) return rows;
  const mult = sortDir === 'asc' ? 1 : -1;
  return [...rows].sort(
    (a, b) =>
      compareValues(cellValue(a, col), cellValue(b, col), col.sortType ?? 'string', locale) * mult,
  );
}

export function nextSortState(
  currentSortBy: string | null | undefined,
  currentSortDir: SortDir | null | undefined,
  columnKey: string,
): { sortBy: string | null; sortDir: SortDir | null } {
  if (currentSortBy !== columnKey) return { sortBy: columnKey, sortDir: 'asc' };
  if (currentSortDir === 'asc') return { sortBy: columnKey, sortDir: 'desc' };
  if (currentSortDir === 'desc') return { sortBy: null, sortDir: null };
  return { sortBy: columnKey, sortDir: 'asc' };
}

export function ariaSortValue(
  sortBy: string | null | undefined,
  sortDir: SortDir | null | undefined,
  columnKey: string,
): 'ascending' | 'descending' | 'none' {
  if (sortBy !== columnKey || !sortDir) return 'none';
  return sortDir === 'asc' ? 'ascending' : 'descending';
}
