const express = require('express');
const config = require('../../config/default');
const logger = require('./utils/logger');
const migrate = require('./storage/migrate');
const { createHttpJsonConnector } = require('./connectors/httpJsonConnector');
const { createHl7TcpConnector } = require('./connectors/hl7TcpConnector');
const { createAstmSerialConnector } = require('./connectors/astmSerialConnector');
const { processMessage } = require('./pipeline/workflow');
const { startWorker, stopWorker } = require('./pipeline/deliveryWorker');
const instrumentService = require('./instrumentConfig/service');
const { createHealthRouter } = require('./routes/health');
const { router: instrumentRouter } = require('./routes/instrumentConfig');
const metricsRouter = require('./routes/metrics');

async function bootstrap() {
  await migrate();
  await instrumentService.init();

  const connectors = [
    createHttpJsonConnector(),
    createHl7TcpConnector(),
    createAstmSerialConnector()
  ];

  connectors.forEach((connector) => {
    connector.onMessage(async (payload) => {
      try {
        await processMessage(connector.name(), payload);
      } catch (err) {
        logger.error({ err: err.message, connector: connector.name() }, 'pipeline error');
      }
    });
    connector.onError((err) => {
      logger.error({ err: err.message }, `${connector.name()} emitted error`);
    });
  });

  await Promise.all(connectors.map((connector) => connector.start()));
  await startWorker();

  const app = express();
  app.use('/health', createHealthRouter(connectors));
  app.use('/instruments', instrumentRouter);
  app.use('/metrics', metricsRouter);
  app.listen(config.healthPort, () => {
    logger.info({ port: config.healthPort }, 'health server ready');
  });

  process.on('SIGINT', async () => {
    logger.info('shutdown signal received');
    await shutdown(connectors);
    process.exit(0);
  });
  process.on('SIGTERM', async () => {
    logger.info('terminate signal received');
    await shutdown(connectors);
    process.exit(0);
  });
}

async function shutdown(connectors) {
  await stopWorker();
  await Promise.all(connectors.map((connector) => connector.stop()));
}

bootstrap().catch((err) => {
  logger.fatal({ err: err.message }, 'failed to start middleware');
  process.exit(1);
});
