import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import React, { useMemo } from 'react';
import { Text, Box } from 'ink';
import { toStyledCharacters, styledCharsToString, styledCharsWidth, wordBreakStyledChars, wrapStyledChars, widestLineFromStyledChars, } from 'ink';
import { theme } from '../semantic-colors.js';
import { RenderInline } from './InlineMarkdownRenderer.js';
import { stripUnsafeCharacters } from './textUtils.js';
const MIN_COLUMN_WIDTH = 5;
const COLUMN_PADDING = 2;
const TABLE_MARGIN = 2;
const calculateWidths = (styledChars) => {
    const contentWidth = styledCharsWidth(styledChars);
    const words = wordBreakStyledChars(styledChars);
    const maxWordWidth = widestLineFromStyledChars(words);
    return { contentWidth, maxWordWidth };
};
/**
 * Custom table renderer for markdown tables
 * We implement our own instead of using ink-table due to module compatibility issues
 */
export const TableRenderer = ({ headers, rows, terminalWidth, }) => {
    // Clean headers: remove bold markers since we already render headers as bold
    // and having them can break wrapping when the markers are split across lines.
    const cleanedHeaders = useMemo(() => headers.map((header) => header.replace(/\*\*(.*?)\*\*/g, '$1')), [headers]);
    const styledHeaders = useMemo(() => cleanedHeaders.map((header) => toStyledCharacters(stripUnsafeCharacters(header))), [cleanedHeaders]);
    const styledRows = useMemo(() => rows.map((row) => row.map((cell) => toStyledCharacters(stripUnsafeCharacters(cell)))), [rows]);
    const { wrappedHeaders, wrappedRows, adjustedWidths } = useMemo(() => {
        const numColumns = styledRows.reduce((max, row) => Math.max(max, row.length), styledHeaders.length);
        // --- Define Constraints per Column ---
        const constraints = Array.from({ length: numColumns }).map((_, colIndex) => {
            const headerStyledChars = styledHeaders[colIndex] || [];
            let { contentWidth: maxContentWidth, maxWordWidth } = calculateWidths(headerStyledChars);
            styledRows.forEach((row) => {
                const cellStyledChars = row[colIndex] || [];
                const { contentWidth: cellWidth, maxWordWidth: cellWordWidth } = calculateWidths(cellStyledChars);
                maxContentWidth = Math.max(maxContentWidth, cellWidth);
                maxWordWidth = Math.max(maxWordWidth, cellWordWidth);
            });
            const minWidth = maxWordWidth;
            const maxWidth = Math.max(minWidth, maxContentWidth);
            return { minWidth, maxWidth };
        });
        // --- Calculate Available Space ---
        // Fixed overhead: borders (n+1) + padding (2n)
        const fixedOverhead = numColumns + 1 + numColumns * COLUMN_PADDING;
        const availableWidth = Math.max(0, terminalWidth - fixedOverhead - TABLE_MARGIN);
        // --- Allocation Algorithm ---
        const totalMinWidth = constraints.reduce((sum, c) => sum + c.minWidth, 0);
        let finalContentWidths;
        if (totalMinWidth > availableWidth) {
            // We must scale all the columns except the ones that are very short(<=5 characters)
            const shortColumns = constraints.filter((c) => c.maxWidth <= MIN_COLUMN_WIDTH);
            const totalShortColumnWidth = shortColumns.reduce((sum, c) => sum + c.minWidth, 0);
            const finalTotalShortColumnWidth = totalShortColumnWidth >= availableWidth ? 0 : totalShortColumnWidth;
            const scale = (availableWidth - finalTotalShortColumnWidth) /
                (totalMinWidth - finalTotalShortColumnWidth);
            finalContentWidths = constraints.map((c) => {
                if (c.maxWidth <= MIN_COLUMN_WIDTH && finalTotalShortColumnWidth > 0) {
                    return c.minWidth;
                }
                return Math.floor(c.minWidth * scale);
            });
        }
        else {
            const surplus = availableWidth - totalMinWidth;
            const totalGrowthNeed = constraints.reduce((sum, c) => sum + (c.maxWidth - c.minWidth), 0);
            if (totalGrowthNeed === 0) {
                finalContentWidths = constraints.map((c) => c.minWidth);
            }
            else {
                finalContentWidths = constraints.map((c) => {
                    const growthNeed = c.maxWidth - c.minWidth;
                    const share = growthNeed / totalGrowthNeed;
                    const extra = Math.floor(surplus * share);
                    return Math.min(c.maxWidth, c.minWidth + extra);
                });
            }
        }
        // --- Pre-wrap and Optimize Widths ---
        const actualColumnWidths = new Array(numColumns).fill(0);
        const wrapAndProcessRow = (row) => {
            const rowResult = [];
            // Ensure we iterate up to numColumns, filling with empty cells if needed
            for (let colIndex = 0; colIndex < numColumns; colIndex++) {
                const cellStyledChars = row[colIndex] || [];
                const allocatedWidth = finalContentWidths[colIndex];
                const contentWidth = Math.max(1, allocatedWidth);
                const wrappedStyledLines = wrapStyledChars(cellStyledChars, contentWidth);
                const maxLineWidth = widestLineFromStyledChars(wrappedStyledLines);
                actualColumnWidths[colIndex] = Math.max(actualColumnWidths[colIndex], maxLineWidth);
                const lines = wrappedStyledLines.map((line) => ({
                    text: styledCharsToString(line),
                    width: styledCharsWidth(line),
                }));
                rowResult.push(lines);
            }
            return rowResult;
        };
        const wrappedHeaders = wrapAndProcessRow(styledHeaders);
        const wrappedRows = styledRows.map((row) => wrapAndProcessRow(row));
        // Use the TIGHTEST widths that fit the wrapped content + padding
        const adjustedWidths = actualColumnWidths.map((w) => 
        // eslint-disable-next-line @typescript-eslint/no-unsafe-return
        w + COLUMN_PADDING);
        return { wrappedHeaders, wrappedRows, adjustedWidths };
    }, [styledHeaders, styledRows, terminalWidth]);
    // Helper function to render a cell with proper width
    const renderCell = (content, width, isHeader = false) => {
        const contentWidth = Math.max(0, width - COLUMN_PADDING);
        // Use pre-calculated width to avoid re-parsing
        const displayWidth = content.width;
        const paddingNeeded = Math.max(0, contentWidth - displayWidth);
        return (_jsxs(Text, { children: [isHeader ? (_jsx(Text, { bold: true, color: theme.text.link, children: _jsx(RenderInline, { text: content.text }) })) : (_jsx(RenderInline, { text: content.text })), ' '.repeat(paddingNeeded)] }));
    };
    // Helper function to render border
    const renderBorder = (type) => {
        const chars = {
            top: { left: '┌', middle: '┬', right: '┐', horizontal: '─' },
            middle: { left: '├', middle: '┼', right: '┤', horizontal: '─' },
            bottom: { left: '└', middle: '┴', right: '┘', horizontal: '─' },
        };
        const char = chars[type];
        const borderParts = adjustedWidths.map((w) => char.horizontal.repeat(w));
        const border = char.left + borderParts.join(char.middle) + char.right;
        return _jsx(Text, { color: theme.border.default, children: border });
    };
    // Helper function to render a single visual line of a row
    const renderVisualRow = (cells, isHeader = false) => {
        const renderedCells = cells.map((cell, index) => {
            // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
            const width = adjustedWidths[index] || 0;
            return renderCell(cell, width, isHeader);
        });
        return (_jsxs(Text, { color: theme.text.primary, children: [_jsx(Text, { color: theme.border.default, children: "\u2502" }), ' ', renderedCells.map((cell, index) => (_jsxs(React.Fragment, { children: [cell, index < renderedCells.length - 1 && (_jsx(Text, { color: theme.border.default, children: ' │ ' }))] }, index))), ' ', _jsx(Text, { color: theme.border.default, children: "\u2502" })] }));
    };
    // Handles the wrapping logic for a logical data row
    const renderDataRow = (wrappedCells, rowIndex, isHeader = false) => {
        const key = isHeader ? 'header' : `${rowIndex}`;
        const maxHeight = Math.max(...wrappedCells.map((lines) => lines.length), 1);
        const visualRows = [];
        for (let i = 0; i < maxHeight; i++) {
            const visualRowCells = wrappedCells.map((lines) => lines[i] || { text: '', width: 0 });
            visualRows.push(_jsx(React.Fragment, { children: renderVisualRow(visualRowCells, isHeader) }, `${key}-${i}`));
        }
        return _jsx(React.Fragment, { children: visualRows }, rowIndex);
    };
    return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [renderBorder('top'), renderDataRow(wrappedHeaders, -1, true), renderBorder('middle'), wrappedRows.map((row, index) => renderDataRow(row, index)), renderBorder('bottom')] }));
};
//# sourceMappingURL=TableRenderer.js.map