"use strict";

const { visWidth, padToWidth } = require("./helpers");

// ─── Grid Renderer ─────────────────────────────────────────────────────────

/** Column gap between cells (spaces, no pipes). */
const COL_GAP = 1;

/**
 * Render a row with equal-width grid columns (no separators).
 * Components returning null are filtered out.
 */
function renderRowGrid(components, termWidth) {
  const active = components.filter(Boolean);
  if (active.length === 0) return null;
  if (active.length === 1) {
    return padToWidth(active[0].out, termWidth);
  }

  const gapOverhead = (active.length - 1) * COL_GAP;
  const baseCol = Math.floor((termWidth - gapOverhead) / active.length);
  const remainder = termWidth - gapOverhead - baseCol * active.length;

  let result = "";
  for (let i = 0; i < active.length; i++) {
    const colW = baseCol + (i < remainder ? 1 : 0);
    if (i > 0) result += " ".repeat(COL_GAP);
    result += padToWidth(active[i].out, colW);
  }
  return result;
}

/** Render a row with flow layout (space-separated, no padding). */
function renderRowFlow(components) {
  const active = components.filter(Boolean);
  if (active.length === 0) return null;
  return active.map((c) => c.out).join(" ".repeat(COL_GAP));
}

/** Maximum grid columns at full width. */
const GRID_COLS = 5;

/** Responsive column count based on terminal width. */
function getGridCols(termWidth) {
  if (termWidth >= 140) return 5;
  if (termWidth >= 100) return 4;
  if (termWidth >= 80) return 3;
  return 2;
}

/**
 * Render all rows as a responsive grid table filling terminal width.
 * Column count adapts: 5 (>=180), 4 (>=140), 3 (>=100), 2 (<100).
 * Rows with more components than columns WRAP into additional rows.
 * Rows with fewer components pad with empty cells.
 */
function renderTable(allRowComponents, termWidth) {
  const gridCols = getGridCols(termWidth);

  // 1. Resolve each row: filter nulls
  const rows = allRowComponents.map((comps) => comps.filter(Boolean));

  // 2. Normalize: wrap overflow into new rows, pad short rows
  const normalized = [];
  for (const row of rows) {
    if (row.length === 0) continue;
    for (let i = 0; i < row.length; i += gridCols) {
      const chunk = row.slice(i, i + gridCols);
      while (chunk.length < gridCols) {
        chunk.push({ vis: "", out: "" });
      }
      normalized.push(chunk);
    }
  }

  // 3. Compute proportional column widths based on content
  const totalGaps = (gridCols - 1) * COL_GAP;
  const usable = termWidth - totalGaps;

  // Find the natural (max content) width for each column position
  const naturalWidths = new Array(gridCols).fill(0);
  for (const row of normalized) {
    for (let c = 0; c < gridCols; c++) {
      const w = visWidth(row[c].vis || row[c].out || "");
      if (w > naturalWidths[c]) naturalWidths[c] = w;
    }
  }

  const totalNatural = naturalWidths.reduce((a, b) => a + b, 0);
  const colWidths = new Array(gridCols).fill(0);

  if (totalNatural <= usable) {
    // Content fits — give each column its natural width, distribute surplus
    // evenly so narrow columns get the same extra padding as wide ones
    const surplus = usable - totalNatural;
    const perCol = Math.floor(surplus / gridCols);
    let leftover = surplus - perCol * gridCols;
    for (let c = 0; c < gridCols; c++) {
      colWidths[c] = naturalWidths[c] + perCol + (leftover > 0 ? 1 : 0);
      if (leftover > 0) leftover--;
    }
  } else {
    // Content overflows — allocate proportional to natural widths so columns
    // stay aligned across rows (equal-width collapses uneven columns and
    // makes long cells spill into neighbors visually).
    let allocated = 0;
    for (let c = 0; c < gridCols; c++) {
      const share = Math.floor((naturalWidths[c] * usable) / totalNatural);
      colWidths[c] = Math.max(share, 1);
      allocated += colWidths[c];
    }
    // Distribute remaining slots to the widest natural columns first.
    let leftover = usable - allocated;
    const widestFirst = naturalWidths
      .map((w, i) => [w, i])
      .sort((a, b) => b[0] - a[0])
      .map(([, i]) => i);
    for (const i of widestFirst) {
      if (leftover <= 0) break;
      colWidths[i]++;
      leftover--;
    }
  }

  // 4. Render each row using the computed column widths
  const lines = [];
  for (const row of normalized) {
    let line = "";
    for (let c = 0; c < gridCols; c++) {
      if (c > 0) line += " ".repeat(COL_GAP);
      line += padToWidth(row[c].out, colWidths[c]);
    }
    lines.push(line);
  }
  return lines;
}

module.exports = {
  COL_GAP,
  GRID_COLS,
  renderRowGrid,
  renderRowFlow,
  getGridCols,
  renderTable,
};
