import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import { ngExpressEngine } from '@nguniversal/express-engine';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { resolve } from 'path';
import { enableProdMode } from '@angular/core';
const domino = require('domino');
const win = domino.createWindow('');
const fetch = require('node-fetch');

global['window'] = win;
global['document'] = win.document;
global['alert'] = console.log
global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
global['fetch'] = fetch.default;

/**
 * Function to attach this SSR application to an express server. Exported as function due to webpack inconsistencies.
 * 
 * @param app express.Application to run on
 * @param staticDir Where the static website content is (i.e. ./dist)
 * @param logger A loggerservice or console
 * @param rateLimiter a rate-limiter-flexible instance
 */
export async function attachExpress(app, staticDir, logger, rateLimiter) {
  const STATIC_FOLDER = resolve(process.cwd(), staticDir);
  enableProdMode();

  const loggerService = {
    warn: (...args) => logger.warn(...args),
    error: (...args) => logger.error(...args),
    log: (...args) => logger.info(...args),
    table: (...args) => logger.info(...args),
    collapsed: (msg, type, ...args) => loggerService[type](msg, ...args)
  }

  const bundle = require(staticDir + '/server/main');

  const ServerApiService = bundle.ServerApiService
  const serviceObj = new ServerApiService(logger)
  await serviceObj.initialize()

  app.set('view engine', 'html');
  app.engine(
    'html',
    ngExpressEngine({
      bootstrap: bundle.AppServerModuleNgFactory,
      providers: [
        provideModuleMap(bundle.LAZY_MODULE_MAP),
        {
          provide: bundle.LoggerService,
          deps: [],
          useValue: loggerService
        },
        {
          provide: bundle.IApiService,
          deps: [],
          useValue: serviceObj,
        }
      ]
    })
  );

  app.get('*', (req, res) => {
    rateLimiter.consume(req.ip, 3)
    .then(_ => {
      res.render(resolve(STATIC_FOLDER, 'browser/index'), { req, res })
    })
    .catch(_ => {
      loggerService.error(String(new Error("429 BAD REQUEST "+req.path+" FROM "+req.ip)))
      res.send("429 Too many requests")
      res.status(429)
    })
  })
}
