import type { QuestionData } from "../../../tool/types.ts";
import type { WrappingSelectItem } from "../wrapping-select.ts";
/** Min terminal/pane width for the side-by-side layout to engage. */
export declare const PREVIEW_MIN_WIDTH = 100;
/** Visual gap between options column and preview column in side-by-side. */
export declare const PREVIEW_COLUMN_GAP = 2;
/** 1 col padding inside the preview column (between gap and `│`). */
export declare const PREVIEW_PADDING_LEFT = 1;
/** Empty rows between options and preview blocks in stacked (narrow) layout. */
export declare const STACKED_GAP_ROWS = 1;
/** Floor for the adaptive left column width — prevents collapse on short labels. */
export declare const MIN_LEFT = 30;
/** Ceiling ratio: left column never exceeds this fraction of pane width. */
export declare const MAX_LEFT_RATIO = 0.5;
/** Floor for the preview column width — prevents right-side collapse on narrow terminals. */
export declare const MIN_PREVIEW_WIDTH = 45;
/** visibleWidth(" ✔") = 2 (space + ✔ codepoint). Reserved on the longest-label measurement
 *  so a confirmed row never gets truncated when MIN_LEFT clamps the column. */
export declare const CONFIRMED_OVERHEAD = 2;
export type PreviewLayoutMode = "side-by-side" | "stacked";
/**
 * Decide layout mode from terminal + pane widths. Pure of inputs.
 *
 * The terminal-width gate is the AND check from the previous `preview-pane.ts` —
 * lifted here so the decision is computed ONCE per render and threaded explicitly
 * through `previewBlockHeight`. Removes the bug class where `previewBlockHeight`
 * re-derived `sideBySide` from a column width (already < pane width post-split),
 * capping height too short.
 */
export declare function decideLayout(terminalWidth: number, paneWidth: number): PreviewLayoutMode;
/**
 * Compute the adaptive left column width from option labels.
 * Pure function — deterministic for a given (items, totalForNumbering, paneWidth).
 *
 * Pipeline:
 *   1. Measure: longest visible label width + prefix overhead + confirmed-mark overhead
 *   2. Clamp: floor MIN_LEFT, ceiling paneWidth * MAX_LEFT_RATIO
 *   3. Safety net: never exceed available = paneWidth - GAP - MIN_PREVIEW_WIDTH
 */
export declare function adaptiveLeftWidth(items: readonly WrappingSelectItem[], totalForNumbering: number, paneWidth: number): number;
/**
 * Cross-tab maximum left-column width. Aggregates `adaptiveLeftWidth` over every tab
 * and returns the widest result, so the options column stays stable on tab switch.
 *
 * Pure function — `tabs.length` MUST equal `itemsByTab.length`. Multi-select tabs
 * use `items.length` for numbering; single-select tabs add 1 for the chat row slot.
 * Floor is `MIN_LEFT` so an all-empty input still produces a usable column.
 */
export declare function crossTabMaxLeftWidth(tabs: ReadonlyArray<{
    multiSelect?: boolean;
}>, itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>, paneWidth: number): number;
/**
 * Source-line probe: measures the widest source line across all options' previews.
 * Returns 0 when no option carries a preview.
 *
 * V1 heuristic — works well for tree/table/heading/list content where source-line
 * width ≈ rendered width. Paragraphs overstate (source width "wants" the full pane);
 * the worst case is "donation does nothing useful" — fallback to the label-driven path.
 * Upgrade path: replace with a render-width probe that invokes Markdown at a probe width.
 *
 * Pure function — O(total chars) per question; no Markdown invocation, no cache interaction.
 */
export declare function previewSourceWidth(question: QuestionData): number;
/**
 * Cross-tab/cross-option preview budget. Iterates all questions, computes each question's
 * preview appetite via `previewSourceWidth`, adds box + padding overhead (5 cols), and
 * returns the widest result. Floor is `MIN_PREVIEW_WIDTH` so a previewless question still
 * reserves a usable column. Ceiling ensures the left column retains its `MIN_LEFT` floor.
 *
 * Pure function — same cross-tab max pattern as `crossTabMaxLeftWidth`.
 */
export declare function crossTabPreviewBudget(questions: readonly QuestionData[], paneWidth: number): number;
/**
 * Cross-tab left-column width with slack donation. Combines the label-driven width
 * (from `crossTabMaxLeftWidth`) with the slack donated by narrow previews.
 *
 * Pipeline:
 *   1. `labelDriven` = `crossTabMaxLeftWidth(tabs, itemsByTab, paneWidth)`
 *   2. `previewBudget` = `crossTabPreviewBudget(questions, paneWidth)`
 *   3. `slackDonation` = `paneWidth − GAP − previewBudget`
 *   4. Return `min(max(labelDriven, slackDonation), ceiling)` where `ceiling = paneWidth − GAP − MIN_PREVIEW_WIDTH`
 *
 * Invariants:
 *   - Floor: result ≥ MIN_LEFT (labelDriven ≥ MIN_LEFT)
 *   - Preview floor: right column ≥ MIN_PREVIEW_WIDTH (ceiling enforces this)
 *   - Cross-tab stability: both reductions are tab-independent
 *   - Determinism: pure of (questions, itemsByTab, paneWidth)
 *
 * `crossTabMaxLeftWidth` is NOT replaced — it continues to exist as the primitive.
 * `MAX_LEFT_RATIO` caps the label-driven path inside `adaptiveLeftWidth`; donation
 * operates above the cap when preview slack is available.
 */
export declare function crossTabLeftWidthWithDonation(tabs: ReadonlyArray<{
    multiSelect?: boolean;
}>, itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>, questions: readonly QuestionData[], paneWidth: number): number;
/**
 * Width allocation for side-by-side mode.
 * `adaptiveLeft` is the pre-computed left column width (from `adaptiveLeftWidth`,
 * cross-tab aggregated). The Math.max(1, ...) calls keep both columns >= 1 col on
 * extreme inputs.
 */
export declare function columnWidths(paneWidth: number, adaptiveLeft: number): {
    leftWidth: number;
    rightWidth: number;
    gap: number;
};
/**
 * Returns the widths actually passed to `options.render` and `previewLines` inside
 * `render()`. Stacked uses the full pane width for both; side-by-side splits via
 * `columnWidths`, with the preview column offset by `PREVIEW_PADDING_LEFT`.
 */
export declare function bodyWidths(paneWidth: number, mode: PreviewLayoutMode, adaptiveLeft: number): {
    optionsWidth: number;
    previewWidth: number;
};
//# sourceMappingURL=preview-layout-decider.d.ts.map