// R2 · 冲突分组/排序 + 跳到下一条未裁决（UX §6.4）。
// 分组仅按 type；严重度排序：已知五类给定优先级，未知殿后。
// 关键：分组/排序只改「显示顺序」，每条仍携原始 index——裁决草稿与 accept 的
// conflict_index 一律以原始下标为准（不变量：conflict_index 覆盖 range(len(conflicts))）。
// 纯逻辑，便于 node 环境单测。

import type { DecisionDraft } from "./decisions";
import type { ReviewConflict } from "./sse";

// 严重度优先级（数字越小越靠前）。对齐 C6 五类 ConflictType。
const SEVERITY_RANK: Record<string, number> = {
  设定违例: 0,
  能力不符: 1,
  时间线倒错: 2,
  地理矛盾: 3,
  性格漂移: 4,
};
const UNKNOWN_RANK = 99;

export interface ConflictItem {
  conflict: ReviewConflict;
  index: number;
}

export interface ConflictGroup {
  type: string;
  items: ConflictItem[];
}

function severityRank(type: string): number {
  return SEVERITY_RANK[type] ?? UNKNOWN_RANK;
}

// 按 type 分组并按严重度排序；组内保留原始出现顺序。
export function groupConflicts(
  conflicts: readonly ReviewConflict[],
): ConflictGroup[] {
  const byType = new Map<string, ConflictItem[]>();
  conflicts.forEach((conflict, index) => {
    const items = byType.get(conflict.type) ?? [];
    items.push({ conflict, index });
    byType.set(conflict.type, items);
  });
  return [...byType.entries()]
    .map(([type, items]) => ({ type, items }))
    .sort((a, b) => severityRank(a.type) - severityRank(b.type));
}

// 显示顺序下的原始下标序列（用于「跳到下一条未裁决」按显示顺序推进）。
export function displayOrder(groups: readonly ConflictGroup[]): number[] {
  return groups.flatMap((group) => group.items.map((item) => item.index));
}

// 显示顺序中、当前聚焦之后的下一条未裁决下标；到末尾环回；无未裁决 → null。
export function nextUnresolvedInOrder(
  order: readonly number[],
  drafts: readonly DecisionDraft[],
  fromIndex: number | null,
): number | null {
  if (order.length === 0) return null;
  const pos = fromIndex === null ? -1 : order.indexOf(fromIndex);
  for (let step = 1; step <= order.length; step++) {
    const idx = order[(pos + step + order.length) % order.length];
    if (idx !== undefined && drafts[idx]?.verdict == null) return idx;
  }
  return null;
}
