// 爽点节拍图：把 pace.beat_map（int 序列）映射成 ▁▃▅ 风格的 sparkline 格子（UX §6.4）。
// 纯逻辑，便于 node 环境单测；渲染时配合高度类与 prefers-reduced-motion。

// 七级火花字符（低→高），与高度档位一一对应。
export const SPARK_CHARS = ["▁", "▂", "▃", "▄", "▅", "▆", "▇"] as const;

export interface BeatCell {
  // 原始强度值。
  value: number;
  // 归一化档位 0..6（映射到 SPARK_CHARS / 高度百分比）。
  level: number;
  // 对应火花字符（▁..▇）。
  char: string;
  // 渲染用高度百分比（12%..100%，最低也可见）。
  heightPct: number;
}

const MIN_HEIGHT_PCT = 12;
const MAX_LEVEL = SPARK_CHARS.length - 1;

// 把 beat_map 映射成可渲染的格子序列。
// 归一化按「本序列 min..max」线性分桶到 0..6；全相等 → 全部居中档（level 3）。
export function toBeatCells(beatMap: readonly number[]): BeatCell[] {
  const values = beatMap.filter((v) => typeof v === "number" && Number.isFinite(v));
  if (values.length === 0) return [];

  const min = Math.min(...values);
  const max = Math.max(...values);
  const span = max - min;

  return values.map((value) => {
    const level =
      span === 0
        ? Math.round(MAX_LEVEL / 2)
        : Math.round(((value - min) / span) * MAX_LEVEL);
    const clamped = Math.min(MAX_LEVEL, Math.max(0, level));
    const heightPct =
      MIN_HEIGHT_PCT + (clamped / MAX_LEVEL) * (100 - MIN_HEIGHT_PCT);
    return {
      value,
      level: clamped,
      char: SPARK_CHARS[clamped] ?? SPARK_CHARS[0],
      heightPct: Math.round(heightPct),
    };
  });
}

// 文本版 sparkline（无障碍/紧凑场景；UX §6.4 示例 ▁▃▅▂▁▇）。
export function toSparkline(beatMap: readonly number[]): string {
  return toBeatCells(beatMap)
    .map((c) => c.char)
    .join("");
}
