/*
 * Copyright (c) 2025, Salesforce, Inc.
 * SPDX-License-Identifier: Apache-2
 * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
 */
/**
 * Table rendering utilities for CLI output.
 *
 * Provides a consistent, flexible way to render tabular data in CLI commands
 * with dynamic column widths based on content.
 *
 * @module cli/table
 *
 * @example
 * ```typescript
 * import { TableRenderer, type ColumnDef } from '@salesforce/b2c-tooling-sdk/cli';
 *
 * interface User {
 *   name: string;
 *   email: string;
 *   role: string;
 * }
 *
 * const columns: Record<string, ColumnDef<User>> = {
 *   name: { header: 'Name', get: (u) => u.name },
 *   email: { header: 'Email', get: (u) => u.email },
 *   role: { header: 'Role', get: (u) => u.role },
 * };
 *
 * const table = new TableRenderer(columns);
 * table.render(users, ['name', 'email', 'role']);
 * ```
 */
import { ux } from '@oclif/core';
import cliui from 'cliui';
/**
 * A reusable table renderer for CLI output.
 *
 * Handles dynamic column width calculation based on content and provides
 * consistent table formatting across all CLI commands.
 *
 * @typeParam T - The type of data items being rendered
 *
 * @example
 * ```typescript
 * // Define columns for your data type
 * const columns: Record<string, ColumnDef<MyData>> = {
 *   id: { header: 'ID', get: (d) => d.id },
 *   name: { header: 'Name', get: (d) => d.name },
 *   status: { header: 'Status', get: (d) => d.status },
 * };
 *
 * // Create renderer and render data
 * const table = new TableRenderer(columns);
 * table.render(items, ['id', 'name', 'status']);
 *
 * // Or with custom options
 * table.render(items, ['id', 'name'], { padding: 3 });
 * ```
 */
export class TableRenderer {
    columns;
    /**
     * Creates a new TableRenderer.
     *
     * @param columns - Column definitions keyed by column identifier
     */
    constructor(columns) {
        this.columns = columns;
    }
    /**
     * Renders data as a formatted table to stdout.
     *
     * @param data - Array of data items to render
     * @param columnKeys - Array of column keys to display (in order)
     * @param options - Optional rendering options
     */
    render(data, columnKeys, options = {}) {
        const termWidth = options.termWidth ?? process.stdout.columns ?? 120;
        const padding = options.padding ?? 2;
        const ui = cliui({ width: termWidth });
        const widths = this.calculateColumnWidths(data, columnKeys, padding);
        // Header row
        const headerCols = columnKeys.map((key) => ({
            text: this.columns[key].header,
            width: widths.get(key),
            padding: [0, 1, 0, 0],
        }));
        ui.div(...headerCols);
        // Separator
        const totalWidth = [...widths.values()].reduce((sum, w) => sum + w, 0);
        ui.div({ text: '─'.repeat(Math.min(totalWidth, termWidth)), padding: [0, 0, 0, 0] });
        // Data rows
        for (const item of data) {
            const rowCols = columnKeys.map((key) => ({
                text: this.columns[key].get(item),
                width: widths.get(key),
                padding: [0, 1, 0, 0],
            }));
            ui.div(...rowCols);
        }
        ux.stdout(ui.toString());
    }
    /**
     * Gets the list of available column keys.
     *
     * @returns Array of all column keys
     */
    getColumnKeys() {
        return Object.keys(this.columns);
    }
    /**
     * Gets column keys excluding extended columns.
     *
     * @returns Array of non-extended column keys
     */
    getDefaultColumnKeys() {
        return Object.entries(this.columns)
            .filter(([, col]) => !col.extended)
            .map(([key]) => key);
    }
    /**
     * Validates and filters column keys.
     *
     * @param requested - Requested column keys
     * @returns Valid column keys that exist in the columns definition
     */
    validateColumnKeys(requested) {
        return requested.filter((key) => key in this.columns);
    }
    /**
     * Calculates dynamic column widths based on content.
     *
     * @param data - Data items to measure
     * @param columnKeys - Columns to calculate widths for
     * @param padding - Padding to add to each column
     * @returns Map of column key to calculated width
     */
    calculateColumnWidths(data, columnKeys, padding) {
        const widths = new Map();
        for (const key of columnKeys) {
            const col = this.columns[key];
            let maxWidth = col.header.length;
            for (const item of data) {
                const value = col.get(item);
                maxWidth = Math.max(maxWidth, value.length);
            }
            const minWidth = col.minWidth ?? 0;
            widths.set(key, Math.max(maxWidth, minWidth) + padding);
        }
        return widths;
    }
}
/**
 * Creates a TableRenderer instance.
 *
 * Convenience function for creating a table renderer.
 *
 * @typeParam T - The type of data items being rendered
 * @param columns - Column definitions
 * @returns A new TableRenderer instance
 *
 * @example
 * ```typescript
 * const table = createTable<User>({
 *   name: { header: 'Name', get: (u) => u.name },
 *   email: { header: 'Email', get: (u) => u.email },
 * });
 * table.render(users, ['name', 'email']);
 * ```
 */
export function createTable(columns) {
    return new TableRenderer(columns);
}
//# sourceMappingURL=table.js.map