/*
 * Copyright (C) 2022 StApps
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
import {Logger} from '@openstapps/logger';
import {execSync} from 'child_process';
import type {ContainerInfo} from 'dockerode';
import mustache from 'mustache';
import {getContainers, getTemplateView} from './main.js';
import {readFile, writeFile} from 'fs/promises';
import {configFile} from './common.js';

/* eslint-disable unicorn/prefer-module */

// handle unhandled promise rejections
process.on('unhandledRejection', async error => {
  await Logger.error(error);
  process.exit(1);
});

let containerHashCache = '';
let configHashCache = '';
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

/**
 * Reads the container information from the docker socket and updates the nginx config if necessary
 */
async function updateNginxConfig() {
  const containers = await getContainers();

  const containerHash = containers
    .map((container: ContainerInfo) => {
      return container.Id;
    })
    .join(',');

  const configHash = JSON.stringify(configFile);

  // if containers changed -> write config file, reload nginx
  if (containerHash !== containerHashCache || configHash !== configHashCache) {
    Logger.log('Generating new NGINX configuration');
    Logger.log('Waiting for Docker network to settle...');
    await delay(10_000);

    // render nginx config file
    const nginxConfig = mustache.render(
      await readFile('nginx.conf.template', 'utf8'),
      await getTemplateView(containers),
    );

    containerHashCache = containerHash;
    configHashCache = configHash;

    Logger.log(`Writing new config file "${configFile.output}"`);

    // overwrite nginx config file with our rendered one
    await writeFile(configFile.output, nginxConfig, 'utf8');

    Logger.log('Executing "nginx -s reload" to tell nginx to reload the configuration file');

    execSync('nginx -s reload');
  }

  // set timeout to update configuration again in 30s
  setTimeout(updateNginxConfig, 30_000);
}

// start the process that checks the docker socket periodically
// eslint-disable-next-line unicorn/prefer-top-level-await
updateNginxConfig();
