export class BatchProcessor {
  constructor(dbManager, config, options = {}) {
    this.dbManager = dbManager;
    this.config = config;
    this.batchSize = options.batchSize || 500;
    this.flushInterval = options.flushInterval || 1000;
    this.buffer = [];
    this.timer = null;
  }

  add(item) {
    return new Promise((resolve, reject) => {
      this.buffer.push({ ...item, resolve, reject });
      if (this.buffer.length >= this.batchSize) {
        this.flush();
      } else if (!this.timer) {
        this.timer = setTimeout(() => this.flush(), this.flushInterval);
      }
    });
  }

  async flush() {
    if (this.buffer.length === 0) return;

    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }

    const currentBatch = [...this.buffer];
    this.buffer = [];

    const allRows = currentBatch.flatMap(item => item.rows);

    if (allRows.length === 0) {
      // No rows to insert (e.g. empty messages), just resolve
      currentBatch.forEach(item => item.resolve(0));
      return;
    }

    try {
      await this.dbManager.insertRows({ 
        schema: this.config.db.schema, 
        table: this.config.db.table, 
        rows: allRows 
      });
      
      // Resolve each item with its own row count
      currentBatch.forEach(item => item.resolve(item.rows.length));
    } catch (error) {
      // Enrich error with DB context if possible (using first item as sample)
      error.type = 'DB_ERROR';
      const sample = allRows[0];
      error.dbContext = {
        batchSize: currentBatch.length,
        totalRows: allRows.length,
        sampleRow: sample ? {
          guid: sample.guid,
          ts_ms: sample.ts_ms,
          action_type: sample.action_type,
          cmd_word: sample.cmd_word
        } : null
      };
      
      // Reject all items in the batch
      currentBatch.forEach(item => item.reject(error));
    }
  }
}
