/**
 * # frame/tape-geometry — the ONE rotated-candlestick geometry both adapters draw (ADR-0052 §1)
 *
 * The tape is a candlestick rotated 90°: price → column position, time flows down. Its 40-column
 * geometry — the price→column projection, the `─` wick low→high, the `█` body open→close, the
 * zero-width-body block, the trailing trim — was materialized twice (the canonical pane in
 * {@link ./pane-catalog.ts renderTape} and the ARM's candlestick style in {@link ./render-arm.ts
 * armTape}). It now lives here once; each adapter keeps only its OWN header + row prefix (which
 * genuinely differ), and both draw the identical candle body from {@link candleLine}.
 *
 * PURE geometry: it derives LAYOUT from the data's own extremes (axis bounds = the input numbers'
 * min/max), never a value. Deterministic — no wall clock, no RNG (RUNTIME §0).
 */
import type { TapeRow } from "./types.ts";

/** Column count for the price axis. A layout constant (not a value); wide enough to *see*
 * drift/range-walls as block migration, narrow enough to stay token-cheap. */
export const TAPE_WIDTH = 40;

/** The tape's price axis bounds — the data's OWN extremes: `lo` = min over every row's low/open/close,
 * `hi` = max over every row's high/open/close. The axis is derived, never invented. PURE. */
export function tapeBounds(rows: readonly TapeRow[]): { readonly lo: number; readonly hi: number } {
  let lo = Infinity;
  let hi = -Infinity;
  for (const r of rows) {
    lo = Math.min(lo, r.low, r.open, r.close);
    hi = Math.max(hi, r.high, r.open, r.close);
  }
  return { lo, hi };
}

/**
 * One row's rotated candle over `[lo, hi]`: a `─` wick spanning low→high and a `█` body spanning
 * open→close, positioned by price → column. A flat window (`span <= 0`) collapses to a single block
 * column; a zero-width body still shows one block. Trailing spaces are trimmed (the leading indent —
 * the low column — is kept: it encodes price level). Returns ONLY the candle cells; the caller owns
 * the row prefix (clock/indent) and the header. PURE.
 */
export function candleLine(row: TapeRow, lo: number, hi: number, width: number = TAPE_WIDTH): string {
  const span = hi - lo;
  const colOf = (p: number): number => {
    if (span <= 0) return 0; // flat window: one column
    const c = Math.round(((p - lo) / span) * (width - 1));
    return c < 0 ? 0 : c > width - 1 ? width - 1 : c;
  };
  const loCol = colOf(row.low);
  const hiCol = colOf(row.high);
  const bodyLo = Math.min(colOf(row.open), colOf(row.close));
  const bodyHi = Math.max(colOf(row.open), colOf(row.close));
  const cells: string[] = Array<string>(width).fill(" ");
  for (let c = loCol; c <= hiCol; c += 1) cells[c] = "─"; // wick low→high
  for (let c = bodyLo; c <= bodyHi; c += 1) cells[c] = "█"; // body open→close
  cells[bodyLo] = "█"; // a zero-width body still shows one block
  return cells.join("").replace(/\s+$/, ""); // keep leading indent, trim trailing
}
