import type { GridValidRowModel } from "@mui/x-data-grid";

import type { DataTableColDef } from "./data-table-types";

/** DataGrid falls back to this when a column sets no width. */
const DEFAULT_COLUMN_WIDTH = 100;

/** Width used by withFixedColumnWidths when a column sets none of its own. */
const DEFAULT_FIXED_COLUMN_WIDTH = 120;

/** How narrow the user may drag a column before it stops shrinking. */
const MIN_RESIZABLE_COLUMN_WIDTH = 80;

/**
 * How wide the table is with every column at its set width.
 *
 * Use this instead of writing the number by hand: a hand-written value stops
 * matching as soon as a column width changes, and the difference shows up as
 * empty space after the last column.
 */
export function getColumnsTotalWidth<Row extends GridValidRowModel>(
  columns: DataTableColDef<Row>[],
  columnVisibility: Record<string, boolean> = {},
): number {
  return columns.reduce((total, column) => {
    if (columnVisibility[column.field] === false) return total;

    const width =
      typeof column.width === "number" ? column.width : DEFAULT_COLUMN_WIDTH;

    return total + width;
  }, 0);
}

/**
 * Hold every column at its configured width so the table scrolls sideways
 * instead of squeezing columns together on a narrow screen.
 *
 * The width is a starting point, not a lock: DataGrid turns resizing on by
 * default, so the user can still drag a column wider or narrower. Setting
 * `maxWidth` here, or a `minWidth` equal to the width, would freeze the column
 * and take that away.
 */
export function withFixedColumnWidths<Row extends GridValidRowModel>(
  columns: DataTableColDef<Row>[],
): DataTableColDef<Row>[] {
  return columns.map((column) => {
    const width =
      typeof column.width === "number" ? column.width : DEFAULT_FIXED_COLUMN_WIDTH;

    return {
      ...column,
      width,
      // A floor, not a lock. Columns already narrower than the floor keep
      // their own width so they are not forced wider than designed.
      minWidth: Math.min(width, MIN_RESIZABLE_COLUMN_WIDTH),
      flex: 0,
    };
  });
}
