/**
 * D0: events.jsonl のイベント列から delegate サブ実行（DelegateRun）を復元する純関数。
 * delegate_start/complete を delegateRunId でペアリングし、correlation 一致の内部
 * イベントを束ねる。complete 欠落 run は 'running' とする。
 */
import type { EventBase } from './event-log.js';

export interface DelegateRun {
  delegateRunId: string;
  parentRunId: string | null;
  description: string;
  depth: number;
  status: 'success' | 'aborted' | 'needs_user_input' | 'running';
  startTs: string;
  endTs: string | null;
  eventCount: number;
  toolCalls: number;
  resultPreview: string | null;
  totalTokens: number;
  toolSummary: Array<{ tool: string; count: number }>;
  filesChanged: string[];
}

function payloadOf(e: EventBase): Record<string, unknown> {
  return (e.payload && typeof e.payload === 'object') ? (e.payload as Record<string, unknown>) : {};
}

export function reconstructDelegateRuns(events: EventBase[]): DelegateRun[] {
  const sorted = [...events].sort((a, b) => a.seq - b.seq);
  const byId = new Map<string, DelegateRun>();
  const order: string[] = [];

  // 1st pass: start でひな型を起こす
  for (const e of sorted) {
    if (e.kind !== 'delegate_start') continue;
    const p = payloadOf(e);
    const id = String(p.delegateRunId ?? '');
    if (!id || byId.has(id)) continue;
    byId.set(id, {
      delegateRunId: id,
      parentRunId: (p.parentRunId == null) ? null : String(p.parentRunId),
      description: String(p.description ?? ''),
      depth: typeof p.depth === 'number' ? p.depth : 1,
      status: 'running',
      startTs: e.ts,
      endTs: null,
      eventCount: 0,
      toolCalls: 0,
      resultPreview: null,
      totalTokens: 0,
      toolSummary: [],
      filesChanged: [],
    });
    order.push(id);
  }

  // 2nd pass: complete でステータス確定、内部イベントを集計
  for (const e of sorted) {
    if (e.kind === 'delegate_complete') {
      const p = payloadOf(e);
      const run = byId.get(String(p.delegateRunId ?? ''));
      if (run) {
        run.endTs = e.ts;
        const s = String(p.status ?? '');
        run.status = (s === 'success' || s === 'aborted' || s === 'needs_user_input') ? s : 'running';
        run.resultPreview = typeof p.resultPreview === 'string' ? p.resultPreview : null;
      }
      continue;
    }
    if (e.kind === 'delegate_start') continue;
    // 内部イベント: correlationId が run の ID に一致するものを束ねる
    if (e.correlationId && byId.has(e.correlationId)) {
      const run = byId.get(e.correlationId)!;
      run.eventCount++;
      if (e.kind === 'tool_call') {
        run.toolCalls++;
        const p = payloadOf(e);
        const tool = typeof p.tool === 'string' ? p.tool : null;
        if (tool) {
          // toolSummary に追加：既存エントリがあれば count を +1、なければ末尾に追加
          const existing = run.toolSummary.find((t) => t.tool === tool);
          if (existing) {
            existing.count++;
          } else {
            run.toolSummary.push({ tool, count: 1 });
          }
          // filesChanged に追加：Write/Edit なら args.file_path を抽出
          if ((tool === 'Write' || tool === 'Edit') && typeof p.args === 'object' && p.args !== null) {
            const args = p.args as Record<string, unknown>;
            const filePath = typeof args.file_path === 'string' ? args.file_path : null;
            if (filePath && !run.filesChanged.includes(filePath)) {
              run.filesChanged.push(filePath);
            }
          }
        }
      }
      if (e.kind === 'llm_call_end') {
        const p = payloadOf(e);
        const promptTokens = typeof p.promptTokens === 'number' ? p.promptTokens : 0;
        const completionTokens = typeof p.completionTokens === 'number' ? p.completionTokens : 0;
        run.totalTokens += promptTokens + completionTokens;
      }
    }
  }

  return order.map((id) => byId.get(id)!);
}
