const net = require('net');
const config = require('../../config/default');
const logger = require('../utils/logger');

function createAstmSerialConnector() {
  let server;
  let messageHandler = async () => {};
  let errorHandler = (err) => logger.error({ err }, 'astm connector error');

  const connections = new Set();

  function attach(socket) {
    connections.add(socket);
    let buffer = '';
    socket.on('data', (chunk) => {
      buffer += chunk.toString('utf8');
      if (buffer.includes('\n')) {
        const [line, ...rest] = buffer.split('\n');
        buffer = rest.join('\n');
        if (line.trim()) {
          messageHandler(line.trim()).catch(errorHandler);
        }
      }
    });
    socket.on('error', (err) => errorHandler(err));
    socket.on('close', () => connections.delete(socket));
  }

  return {
    name: () => 'astm-serial',
    type: () => 'astm-serial',
    async start() {
      server = net.createServer(attach);
      return new Promise((resolve, reject) => {
        server.listen(config.connectors.astmTcpPort, () => {
          logger.info({ port: config.connectors.astmTcpPort }, 'astm serial connector listening');
          resolve();
        });
        server.on('error', (err) => {
          errorHandler(err);
          reject(err);
        });
      });
    },
    async stop() {
      for (const socket of connections) {
        socket.destroy();
      }
      if (!server) return;
      return new Promise((resolve, reject) => {
        server.close((err) => {
          if (err) return reject(err);
          resolve();
        });
      });
    },
    health() {
      return { status: server ? 'up' : 'down', port: config.connectors.astmTcpPort };
    },
    onMessage(handler) {
      messageHandler = handler;
    },
    onError(handler) {
      errorHandler = handler;
    }
  };
}

module.exports = { createAstmSerialConnector };
