import { NileGrid } from './nile-grid';
import {  takeFromRight, giveToRight, totalReducibleRight } from './nile-grid.width';
import { applyColumnsTemplate } from './nile-grid.layout';

/**
 * @param minColumnWidth Minimum allowed column width
 * @param resizeStart Guide line element (start)
 * @param resizeEnd Guide line element (end)
 * @param col Active column index
 * @param scrollHeight Height to apply to guides
 * @param columnWidths Current column widths
 * @returns void
 */
export const resizeLinesHandler = (
  minColumnWidth: number,
  resizeStart: HTMLElement,
  resizeEnd: HTMLElement,
  col: number,
  scrollHeight: number,
  columnWidths: number[],
) => {
  resizeStart.style.display = 'block';
  resizeEnd.style.display = 'block';
  resizeStart.style.height = scrollHeight + 'px';
  resizeEnd.style.height = scrollHeight + 'px';
  const floor = minColumnWidth;
  const safe = (n: number) => Math.max(0, Math.round(n || 0));
  const sum = (arr: number[], endExclusive: number) => safe(arr.slice(0, Math.max(0, endExclusive)).reduce((a, b) => a + (b || 0), 0));

  const totalGridWidth = safe(columnWidths.reduce((a, b) => a + (b || 0), 0));
  const baseLeft = sum(columnWidths, col);
  const appliedColWidth = safe(Math.max(floor, columnWidths[col] ?? floor));
  let handleLeft = baseLeft + appliedColWidth;

  const minEdge = baseLeft + floor;
  const maxEdge = totalGridWidth;
  handleLeft = Math.min(Math.max(handleLeft, minEdge), maxEdge);
  handleLeft = Math.max(handleLeft, 20);

  resizeStart.style.left = `${handleLeft - 6}px`;
  resizeEnd.style.left = `${handleLeft - 2}px`;
};

/**
 * @param targetWidth New computed width in pixels
 * @param min Minimum allowed width
 * @param max Maximum allowed width
 * @returns Adjusted column width
 */
export function computeNewWidth(opts: {
  target: HTMLElement;
  col: number;
  widthPx: number;
  floor: number;
  columnWidths: number[];
}) {
  const { target, col, widthPx, floor, columnWidths } = opts;

  // move this outside - getAttribute
  const hasSpan =
    !!target.getAttribute('colspan') &&
    parseInt(target.getAttribute('colspan')!, 10) > 1;
  const prevW = columnWidths[col] ?? floor;
  const newWraw = hasSpan ? widthPx - (columnWidths[col - 1] ?? 0) : widthPx;
  const newW = Math.max(floor, Math.round(Number.isFinite(newWraw) ? newWraw : prevW));
  return { prevW, newW, delta0: newW - prevW };
}

/**
 * @param columnWidths Current widths array
 * @param containerWidth Container total width
 */
export function resizeNoScroll({ grid, col, prevW, newW, floor }: {
  grid: NileGrid;
  col: number;
  prevW: number;
  newW: number;
  floor: number;
}) {
  if (grid.lockedWidthColumns?.[col]) return;
  let delta = newW - prevW;
  if (delta > 0) {
    const rightReducible = totalReducibleRight(grid.columnWidths, col + 1, floor, grid.lockedWidthColumns);
    if (rightReducible <= 0) return;
    delta = Math.min(delta, rightReducible);
    grid.columnWidths[col] = prevW + delta;
    takeFromRight(grid.columnWidths, col + 1, delta, floor, grid.lockedWidthColumns);
  } else {
    const newColW = Math.max(floor, newW);
    const actualShrink = prevW - newColW;
    grid.columnWidths[col] = newColW;
    giveToRight(grid.columnWidths, col + 1, actualShrink);
  }
}

/**
 * @param columnWidths Current widths
 * @param containerWidth Container width
 */
export function resizeWithScroll(opts: {
  grid: NileGrid;
  col: number;
  newW: number;
}) {
  const { grid, col, newW } = opts;
  if (grid.lockedWidthColumns?.[col]) return;
  grid.columnWidths[col] = newW;
}

/**
 * @param el Target element within grid
 * @returns Scrollbar width compensation value
 */
export function getScrollbarComp(el: HTMLElement) {
  const scroller = el.closest('nile-grid') as HTMLElement | null;
  return scroller ? scroller.offsetWidth - scroller.clientWidth : 0;
}

/**
 * @param nileGrid The parent grid
 * @param columnWidths New column width array
 */
export function applyAfterResize(grid: any, col: number) {
  resizeLinesHandler(
    grid.minColumnWidth,
    grid.resizeStart,
    grid.resizeEnd,
    col,
    grid.scrollHeight,
    grid.columnWidths
  );
  applyColumnsTemplate(grid, grid.columnWidths);
}

export function updateResizeGuides(grid: NileGrid, col: number) {
  resizeLinesHandler(
    grid.minColumnWidth,
    grid.resizeStart,
    grid.resizeEnd,
    col,
    grid.scrollHeight,
    grid.columnWidths
  );
}