'use strict';

const {
  createRunEnvelope,
  toBrainMemorySummary,
  toCtmSessionPatch,
  updateRunEnvelope,
} = require('./run-envelope');

function createRunTrace(input = {}, { clock = () => new Date().toISOString() } = {}) {
  const envelope = createRunEnvelope(input, { clock });
  const events = [];

  function append(type, data = {}) {
    const event = {
      id: data.id || `${type}-${events.length + 1}`,
      type,
      at: data.at || clock(),
      data: { ...data },
    };
    delete event.data.id;
    delete event.data.at;
    events.push(event);
    applyEvent(event);
    return event;
  }

  function applyEvent(event) {
    if (event.type === 'status') {
      Object.assign(envelope, updateRunEnvelope(envelope, {
        status: event.data.status,
        statusReason: event.data.reason || event.data.statusReason || '',
        terminal: event.data.terminal || {},
      }, { clock }));
      return;
    }
    if (event.type === 'tool') {
      const next = { ...(envelope.toolSummary || {}) };
      next.total = (next.total || 0) + 1;
      if (event.data.status === 'failed') next.failed = (next.failed || 0) + 1;
      const sideEffect = event.data.sideEffect || 'read';
      next[sideEffect] = (next[sideEffect] || 0) + 1;
      const changedFiles = new Set(next.changedFiles || []);
      for (const file of event.data.changedFiles || []) changedFiles.add(file);
      next.changedFiles = [...changedFiles];
      Object.assign(envelope, updateRunEnvelope(envelope, { toolSummary: next }, { clock }));
      return;
    }
    if (event.type === 'compaction') {
      Object.assign(envelope, updateRunEnvelope(envelope, {
        compaction: {
          compacted: true,
          count: (envelope.compaction?.count || 0) + 1,
          tokensBefore: event.data.tokensBefore,
          tokensAfter: event.data.tokensAfter,
          lastCompactionId: event.data.compactionId || event.id,
        },
      }, { clock }));
      return;
    }
    if (event.type === 'usage') {
      Object.assign(envelope, updateRunEnvelope(envelope, { usage: event.data }, { clock }));
    }
  }

  function snapshot() {
    return {
      envelope: { ...envelope, metadata: { ...(envelope.metadata || {}) } },
      events: events.map(event => ({ ...event, data: { ...event.data } })),
    };
  }

  return {
    append,
    snapshot,
    terminalMetadata: () => ({ ...(envelope.terminal || {}), status: envelope.status }),
    toCtmSessionPatch: () => toCtmSessionPatch(envelope),
    toBrainMemorySummary: () => toBrainMemorySummary(envelope),
  };
}

module.exports = {
  createRunTrace,
};
