import { computed, signal, type Signal } from '@angular/core';
import type { RowSelectionState } from '@tanstack/angular-table';

export interface TableSelectionAtom {
  readonly ids: Signal<Set<string>>;
  toggleId(id: string): void;
  setIds(newIds: string[] | Set<string>): void;
  clear(): void;
  isSelected(id: string): boolean;
  /**
   * Derives a TanStack `RowSelectionState` from the internal Set + a
   * reactive list of currently-visible row ids. The result includes only
   * visible ids that are also in the Set, while the internal Set preserves
   * any id that fell out of the visible window — that's the cross-page
   * persistence guarantee. The host typically passes the visible ids from
   * `data().rows.map(r => r.id)`.
   */
  toRowSelectionState(visibleIds: Signal<string[]>): Signal<RowSelectionState>;
}

/**
 * Atom: row selection by id. Single responsibility — owns a `Set<string>`
 * of selected ids. The Set survives any change in the visible row window
 * (paginate/sort/filter), making cross-page bulk operations possible.
 *
 * The host wires this atom to TanStack via the binding layer (`useDataTable`)
 * by passing `getRowId: r => r.id` and using `toRowSelectionState(...)` to
 * derive the TanStack `state.rowSelection`.
 */
export function useTableSelection(initialIds: string[] = []): TableSelectionAtom {
  const ids = signal<Set<string>>(new Set(initialIds));

  function toggleId(id: string): void {
    const next = new Set(ids());
    if (next.has(id)) next.delete(id);
    else next.add(id);
    ids.set(next);
  }

  function setIds(newIds: string[] | Set<string>): void {
    ids.set(new Set(newIds));
  }

  function clear(): void {
    ids.set(new Set());
  }

  function isSelected(id: string): boolean {
    return ids().has(id);
  }

  function toRowSelectionState(visibleIds: Signal<string[]>): Signal<RowSelectionState> {
    return computed(() => {
      const set = ids();
      const state: RowSelectionState = {};
      for (const id of visibleIds()) {
        if (set.has(id)) state[id] = true;
      }
      return state;
    });
  }

  return {
    ids: ids.asReadonly(),
    toggleId,
    setIds,
    clear,
    isSelected,
    toRowSelectionState,
  };
}
