import type { Lang } from '../core/types';

import type { LayoutCandidate, LayoutCandidateLine, ScoredLayout, TextWrapContext } from './types';

function asInt(n: number): number {
  return n | 0;
}

function roundToInt(n: number): number {
  return Math.round(n);
}

function lineWidthOrApprox(line: LayoutCandidateLine, lang: Lang): number {
  if (typeof line.width === 'number' && Number.isFinite(line.width)) return roundToInt(line.width);
  return lang === 'EN' ? asInt(line.tokenCount) : asInt(line.charCount);
}

function computeIdealBreakPositions(nTokens: number, lineCount: number): number[] {
  const n = Math.max(0, nTokens | 0);
  const targetLines = Math.max(1, Math.min(lineCount | 0, n === 0 ? 1 : n));
  const ideals: number[] = [];

  for (let i = 1; i <= targetLines - 1; i++) {
    ideals.push(Math.round((n * i) / targetLines));
  }

  ideals.sort((a, b) => a - b);
  return ideals.filter((v, idx) => idx === 0 || v !== ideals[idx - 1]);
}

function sumAbs(a: number[], b: number[]): number {
  const m = Math.min(a.length, b.length);
  let s = 0;
  for (let i = 0; i < m; i++) s += Math.abs((a[i] ?? 0) - (b[i] ?? 0));
  // 若长度不等，用一个确定性惩罚补齐（避免 NaN，并让更“匹配理想结构”的更优）
  if (a.length !== b.length) s += 100000 * Math.abs(a.length - b.length);
  return s;
}

function computeSpread(widths: number[]): number {
  if (widths.length === 0) return 0;
  let min = widths[0]!;
  let max = widths[0]!;
  for (const w of widths) {
    if (w < min) min = w;
    if (w > max) max = w;
  }
  return max - min;
}

export type BuildTieKeyInput = {
  scoredLayout: ScoredLayout;
  layoutCandidate: LayoutCandidate;
  lang: Lang;
  context: TextWrapContext;
  /** tokens.length（用于理想切分点距离；必须与 breaks/lines 的 token 体系一致） */
  tokenCount: number;
  /** 可用宽度（用于理想切分点/尾行宽度判断的辅助项；tieKey 主要使用 width 值） */
  availableWidth: number;
  idealWidthRatio: { APP: number; WIDGET: number };
};

/**
 * 构造 tieKey（按文档 11 节顺序，必须确定性）：
 * 1) emotionSplit=false 优先
 * 2) overflowed=false 优先
 * 3) lastLineWidth 更大优先
 * 4) 行宽分布更均匀优先（max-min 更小）
 * 5) 断点更接近理想切分点优先（距离之和更小）
 * 6) breaks 字典序更靠前优先（在外部比较中按逐项数值比较即可）
 */
export function buildTieKey(args: BuildTieKeyInput): Array<number | string> {
  const { scoredLayout, layoutCandidate } = args;
  const lines = layoutCandidate.lines ?? [];
  const breaks = (layoutCandidate.breaks ?? []).slice().sort((a, b) => a - b);

  const widths = lines.map((l) => lineWidthOrApprox(l, args.lang));
  const lastLineWidth = widths.length > 0 ? widths[widths.length - 1]! : 0;
  const spread = computeSpread(widths);

  const ideals = computeIdealBreakPositions(args.tokenCount, lines.length);
  const idealDist = sumAbs(breaks, ideals);

  const emotionSplitFlag = scoredLayout.flags.emotionSplit ? 1 : 0;
  const overflowedFlag = scoredLayout.flags.overflowed ? 1 : 0;

  return [
    emotionSplitFlag,
    overflowedFlag,
    -lastLineWidth, // 更大优先 => 取负数实现“更小更优”
    spread, // 更小更优
    idealDist, // 更小更优
    ...breaks,
  ];
}

