import { flexRenderComponent, type ColumnPinningState } from '@tanstack/angular-table';
import { SortButton } from '../components/sort-button.component';
import type { DataTableColumnDef, LabeledColumn } from '../types';

/**
 * Builds the initial `ColumnPinningState` for TanStack's column pinning from
 * the declarative `sticky` field on each `DataTableColumnDef`. Columns
 * declaring `sticky: 'left'` (in declaration order) seed `left`; same for
 * `sticky: 'right'` and `right`. The resulting state is passed to
 * `initialState.columnPinning` when the table is created.
 */
export function derivePinningState<T>(columns: DataTableColumnDef<T>[]): ColumnPinningState {
  const left: string[] = [];
  const right: string[] = [];
  for (const column of columns) {
    if (!column.id) continue;
    if (column.sticky === 'left') left.push(column.id);
    else if (column.sticky === 'right') right.push(column.id);
  }
  return { left, right };
}

/**
 * Resolves a label that can be either a static string or a function returning a string.
 */
export function resolveLabel(label: string | (() => string)): string {
  return typeof label === 'function' ? label() : label;
}

/**
 * Adds default SortButton headers to columns with `sortable: true`, a `label`, and no
 * explicit `header`. Called internally by `useDataTable`.
 */
export function applySortHeaders<T>(columns: DataTableColumnDef<T>[]): DataTableColumnDef<T>[] {
  return columns.map((col) => {
    if (col.header || !col.sortable || !col.label) return col;
    const labelFn = typeof col.label === 'function' ? col.label : () => col.label as string;
    return Object.assign({}, col, {
      header: () =>
        flexRenderComponent(SortButton, {
          inputs: { label: labelFn() },
        }),
    });
  });
}

export function getFilterableColumns<T>(columns: DataTableColumnDef<T>[]): LabeledColumn[] {
  return columns
    .filter(
      (col): col is DataTableColumnDef<T> & { id: string; label: string | (() => string) } =>
        !!col.filterable && !!col.id && !!col.label,
    )
    .map((col) => ({ key: col.id, label: resolveLabel(col.label) }));
}

export function getExportableColumns<T>(columns: DataTableColumnDef<T>[]): LabeledColumn[] {
  return columns
    .filter(
      (col): col is DataTableColumnDef<T> & { id: string; label: string | (() => string) } =>
        !!col.exportable && !!col.id && !!col.label,
    )
    .map((col) => ({ key: col.id, label: resolveLabel(col.label) }));
}

export function getToggleableColumns<T>(columns: DataTableColumnDef<T>[]): LabeledColumn[] {
  return columns
    .filter(
      (col): col is DataTableColumnDef<T> & { id: string; label: string | (() => string) } =>
        !!col.id && !!col.label,
    )
    .map((col) => ({ key: col.id, label: resolveLabel(col.label) }));
}

export function getSearchableColumnIds<T>(columns: DataTableColumnDef<T>[]): string[] {
  return columns
    .filter((col): col is DataTableColumnDef<T> & { id: string } => !!col.searchable && !!col.id)
    .map((col) => col.id);
}
