export interface ExecDetailGroupRow {
  serverId: string
  serverIdNum: number
  serverName: string
  serverDomain: string
  status: string
  phase?: string
  exitCode: number | null
  summary: string
  fullOutput: string
  failed: boolean
  pending: boolean
}

export interface ExecDetailFailureGroup {
  errorKey: string
  rows: ExecDetailGroupRow[]
  count: number
}

/** Strip IPs, ports, paths and collapse whitespace for grouping similar SSH errors. */
export function stripDynamicErrorParts(text: string): string {
  return text
    .replace(/\b\d{1,3}(?:\.\d{1,3}){3}\b/g, '<ip>')
    .replace(/:\d{2,5}\b/g, ':<port>')
    .replace(/\/[^\s'"]+/g, '/<path>')
    .replace(/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi, '<uuid>')
    .replace(/\s+/g, ' ')
    .trim()
}

/** Normalize error summary for grouping (first line, dynamic parts stripped, capped). */
export function normalizeExecErrorKey(summary: string): string {
  const trimmed = summary.trim()
  if (!trimmed || trimmed === '—') return '未知错误'
  const firstLine = trimmed.split('\n')[0]?.trim() || trimmed
  const normalized = stripDynamicErrorParts(firstLine)
  return normalized.slice(0, 200) || '未知错误'
}

export function groupFailedExecRows(rows: ExecDetailGroupRow[]): ExecDetailFailureGroup[] {
  const map = new Map<string, ExecDetailGroupRow[]>()
  for (const row of rows) {
    if (!row.failed) continue
    const key = normalizeExecErrorKey(row.summary)
    const list = map.get(key)
    if (list) list.push(row)
    else map.set(key, [row])
  }
  return [...map.entries()]
    .map(([errorKey, groupRows]) => ({
      errorKey,
      rows: groupRows.sort((a, b) => a.serverName.localeCompare(b.serverName, 'zh')),
      count: groupRows.length,
    }))
    .sort((a, b) => b.count - a.count || a.errorKey.localeCompare(b.errorKey, 'zh'))
}
