'use strict';
// Integraties: open API-events, uitgaande webhooks, anomaliedetectie en sessie-replay.
// Geen dependencies — gebruikt alleen Node's http/https.
const http = require('http');
const https = require('https');

function postJson(url, body, headers) {
  try {
    const u = new URL(url);
    const lib = u.protocol === 'https:' ? https : http;
    const data = Buffer.from(JSON.stringify(body));
    const req = lib.request(u, {
      method: 'POST',
      timeout: 8000,
      headers: Object.assign({ 'Content-Type': 'application/json', 'Content-Length': data.length }, headers || {}),
    }, (res) => { res.on('data', () => {}); res.on('end', () => {}); });
    req.on('error', () => {});
    req.on('timeout', () => req.destroy());
    req.write(data); req.end();
  } catch (_) {}
}

function createIntegrations(opts) {
  const log = opts.log || (() => {});
  let cfg = {};                       // { apiKey, webhooks:[url], anomaly:{ stuckSec, enabled }, cloudPush:{ url, key } }
  const replay = { on: false, frames: [], max: 3600, t0: 0 };   // ~30 min @ 500ms
  const occSince = {};                // block-id -> ms sinds bezet
  const firedAnom = {};               // anomalie-sleutel -> al gemeld?
  let listeners = [];                 // extra event-sinks (mqtt, lights)
  let prevConn = false, prevSensors = {};

  function configure(c) { cfg = c || {}; }
  function onEvent(fn) { listeners.push(fn); }

  // Centrale event-emitter: naar log, webhooks, cloud-push (anomalie) en extra sinks.
  function event(type, data) {
    const ev = Object.assign({ type: type, ts: new Date().toISOString() }, data);
    for (const fn of listeners) { try { fn(ev); } catch (_) {} }
    const hooks = Array.isArray(cfg.webhooks) ? cfg.webhooks : [];
    for (const url of hooks) if (url) postJson(url, ev, cfg.apiKey ? { 'X-MRP-Key': cfg.apiKey } : null);
    if (type === 'anomaly' && cfg.cloudPush && cfg.cloudPush.url) {
      postJson(cfg.cloudPush.url, { key: cfg.cloudPush.key || '', title: data.title || 'Baan-anomalie', body: data.message || '', kind: data.kind || '' });
    }
  }

  // Per-tick: anomaliedetectie + replay-opname + sensor/verbinding-events.
  function tick(snap) {
    const now = Date.now();
    const sensors = snap.sensors || {};
    // sensor enter/exit events (server-kant, voor webhooks/mqtt/replay-markers)
    for (const id of Object.keys(Object.assign({}, sensors, prevSensors))) {
      const a = !!sensors[id], b = !!prevSensors[id];
      if (a && !b) event('block_enter', { block: id });
      else if (!a && b) event('block_exit', { block: id });
    }
    prevSensors = Object.assign({}, sensors);

    // verbinding verloren
    if (prevConn && !snap.connected) event('anomaly', { kind: 'conn_lost', title: 'Verbinding met centrale weg', message: 'De centrale reageert niet meer.' });
    prevConn = snap.connected;

    // anomalie: blok blijft te lang bezet (mogelijk vastgelopen/ontspoord materieel)
    const stuckSec = (cfg.anomaly && cfg.anomaly.stuckSec) || 600;
    const anomOn = !cfg.anomaly || cfg.anomaly.enabled !== false;
    if (anomOn && snap.power) {
      for (const id of Object.keys(sensors)) {
        if (sensors[id]) {
          if (!occSince[id]) occSince[id] = now;
          else if (now - occSince[id] > stuckSec * 1000 && !firedAnom['stuck:' + id]) {
            firedAnom['stuck:' + id] = true;
            event('anomaly', { kind: 'block_stuck', block: id, title: 'Blok blijft bezet', message: 'Blok ' + id + ' is al ' + Math.round((now - occSince[id]) / 1000) + ' s bezet.' });
          }
        } else { delete occSince[id]; delete firedAnom['stuck:' + id]; }
      }
    } else { for (const k of Object.keys(occSince)) delete occSince[k]; }

    // replay-opname
    if (replay.on) {
      const locos = {};
      for (const a of Object.keys(snap.locos || {})) { const l = snap.locos[a]; locos[a] = { s: l.speed || 0, d: l.dir }; }
      replay.frames.push({ t: replay.t0 ? now - replay.t0 : 0, locos: locos, sensors: Object.assign({}, sensors), turnouts: Object.assign({}, snap.turnouts || {}), signals: (snap.signals || []).map((x) => ({ id: x.id, a: x.aspect })) });
      if (replay.frames.length > replay.max) replay.frames.shift();
    }
  }

  function startReplay() { replay.on = true; replay.frames = []; replay.t0 = Date.now(); log('⏺️ Sessie-replay opname gestart'); }
  function stopReplay() { replay.on = false; log('⏹️ Sessie-replay opname gestopt (' + replay.frames.length + ' frames)'); }
  function replayData() { return { recording: replay.on, count: replay.frames.length, frames: replay.frames }; }
  function replayStatus() { return { recording: replay.on, count: replay.frames.length }; }

  return { configure, event, tick, onEvent, startReplay, stopReplay, replayData, replayStatus };
}

module.exports = { createIntegrations, postJson };
