'use strict';

const net = require('net'),
      winston = require('winston'),
      PagerDuty = require('./lib/pagerduty'),
      {nconf} = require('./lib/config'),
      {ForwardClient} = require('./lib/forward-client'),
      {Msg, Reader, serialize, deserialize} = require('./lib/proto');

// for the pairwise operator
require('rxjs/add/operator/pairwise');

const transports = [];
if (nconf.get('log:file')) {
    transports.push(
        new (winston.transports.File)({filename: nconf.get('log:file')})
    );
}
if (nconf.get('log:console')) {
    const colorize = nconf.get('log:console') === 'color';
    transports.push(
        new (winston.transports.Console)({colorize: colorize})
    );
}

const listenPort = nconf.get('listen:port'),
      listenHost = nconf.get('listen:host'),
      forward = nconf.get('forward'),
      maxMessageLength = nconf.get('listen:maxMessageLength'),
      hostname = nconf.get('hostname'),
      pager = new PagerDuty(nconf.get('pagerduty:serviceKey')),
      OK = serialize(new Msg(true)),
      logger = new (winston.Logger)({
          level: nconf.get('log:level'),
          transports: transports
      });

const forwarder = new ForwardClient(
    logger,
    forward.host,
    forward.port,
    forward.minFlushEvents,
    forward.maxBufferEvents,
    forward.maxFlushInterval,
    forward.reconnectTimeout)

const stateChangeStream = forwarder.lostEventsCounter
    .bufferTime(2000)
    .map(events => events.length === 0 ? 'passed' : 'failed')
    .pairwise()
    .filter(([a, b]) => a !== b)
    .map(([first,  second]) => second);

stateChangeStream.subscribe(state => {
    const func = state === 'failed' ? 'error' : 'info';
    logger[func]('Forward client state changed to',  state);

    const service = 'fritz event loss';
    const incidentKey = hostname + ' ' + service;
    const eventType = state === 'failed' ? 'trigger' : 'resolve';
    pager.call({
        incidentKey,
        eventType,
        details: {
            time: new Date().getTime(),
            host: hostname,
            service: service,
            state: state,
            reason: reason,
        },
        description: incidentKey + " is " + state + ' (' + forwarder.lostEventsCounter.getValue() + ')'
    });
});

for (const key of ['conf', 'listen', 'forward', 'log', 'pagerduty']) {
    logger.debug('config.' + key + ':', nconf.get(key));
}

forwarder.connect();

const server = net.createServer((socket) => {
    const clientRepr = socket.remoteAddress + ':' + socket.remotePort;
    const reader = new Reader(maxMessageLength);
    logger.info('client connected on', clientRepr);
    socket.on('data', (data) => {
        logger.silly('<<', data);
        try {
            const messages = reader.readMessagesFromBuffer(data);
            for (const raw of messages) {
                const msg = deserialize(raw);
                logger.debug('Read message from', clientRepr, ':', msg);
                socket.write(OK);
                forwarder.enqueue(msg.events);
            }
        } catch (error) {
            logger.error('Exception in socket', clientRepr, ':', error);
            socket.end();
        }
    })
    .on('end', () => {
        logger.info('client diconnected on', clientRepr);
    })
    .on('error', (err) => {
        logger.error('client error on', clientRepr, ':', err);
    });
});

server.listen(listenPort, listenHost, () => {
    logger.info('server listening on', listenHost + ':' + listenPort);
});

@@ -1895,16 +1895,79 @@
 solve';%0A
+    const lostEvents = forwarder.lostEventsCounter.getValue();%0A
     page
@@ -2117,17 +2117,8 @@
     
- service:
  ser
@@ -2138,15 +2138,8 @@
     
- state:
  sta
@@ -2158,23 +2158,18 @@
     
-reason: reason,
+lostEvents
 %0A   
@@ -2239,46 +2239,18 @@
 ' + 
-forwarder.lostEventsCounter.getValue()
+lostEvents
  + '

reason was undefined