'use strict';

const metrics = require('./metrics');

const MAX_ATTEMPTS = 8;
const BASE_DELAY_MS = 500;

const queue = [];
let timer = null;

function schedule(target, event, attempt) {
  attempt = attempt || 1;

  if (attempt > MAX_ATTEMPTS) {
    metrics.increment('events.dropped');
    return;
  }

  const delay = BASE_DELAY_MS * Math.pow(2, attempt - 1);
  queue.push({ target, event, attempt, runAt: Date.now() + delay });
  metrics.increment('retry.scheduled');

  if (!timer) {
    timer = setInterval(drain, 250);
  }
}

function drain() {
  const now = Date.now();
  const ready = queue.filter((item) => item.runAt <= now);

  for (const item of ready) {
    const idx = queue.indexOf(item);
    if (idx !== -1) queue.splice(idx, 1);
    attemptDelivery(item);
  }

  if (queue.length === 0 && timer) {
    clearInterval(timer);
    timer = null;
  }
}

function attemptDelivery(item) {
  const http = require('http');
  const req = http.request(item.target.endpoint, { method: 'POST' }, (res) => {
    if (res.statusCode >= 200 && res.statusCode < 300) {
      metrics.increment('events.delivered');
    } else {
      schedule(item.target, item.event, item.attempt + 1);
    }
  });
  req.on('error', () => schedule(item.target, item.event, item.attempt + 1));
  req.write(JSON.stringify(item.event));
  req.end();
}

function queueDepth() {
  return queue.length;
}

module.exports = { schedule, drain, queueDepth };
