// wall-e/tools/coding-events.js
// Inspired by OpenCode's Bus service
// (https://github.com/anomalyco/opencode, packages/opencode/src/bus/)
// Fire-and-forget pub/sub for coding agent lifecycle events.
'use strict';

const EventEmitter = require('node:events');

class CodingEvents {
  constructor() {
    this._emitter = new EventEmitter();
    this._emitter.setMaxListeners(50); // coding agent has many subscribers
  }

  on(event, handler) {
    // Wrap handler to isolate errors
    const safeHandler = (...args) => {
      try {
        handler(...args);
      } catch (err) {
        console.error(`[coding-events] Error in ${event} listener:`, err.message);
      }
    };
    safeHandler._original = handler; // for off() matching
    this._emitter.on(event, safeHandler);
  }

  off(event, handler) {
    const listeners = this._emitter.listeners(event);
    for (const listener of listeners) {
      if (listener._original === handler) {
        this._emitter.off(event, listener);
        return;
      }
    }
  }

  emit(event, data) {
    this._emitter.emit(event, data);
  }

  clear() {
    this._emitter.removeAllListeners();
  }
}

// Standard event names
const Events = {
  FILE_EDITED: 'file.edited',
  FILE_CREATED: 'file.created',
  FILE_DELETED: 'file.deleted',
  FILE_READ: 'file.read',
  CONTEXT_OVERFLOW: 'context.overflow',
  // Interactive questions (B1) — inspired by OpenCode Question events
  QUESTION_ASKED: 'question.asked',
  QUESTION_REPLIED: 'question.replied',
  QUESTION_REJECTED: 'question.rejected',
  // Coding agent lifecycle events (Phase 6)
  TEST_PASSED: 'test.passed',
  TEST_FAILED: 'test.failed',
  PLAN_CREATED: 'plan.created',
  SUBTASK_COMPLETED: 'subtask.completed',
  MODEL_SWITCHED: 'model.switched',
  DOOM_LOOP_DETECTED: 'doom_loop.detected',
  SESSION_EVALUATED: 'session.evaluated',
};

module.exports = { CodingEvents, Events };
