/**
 * Koa              : http://koajs.com/
 * Koa middleware   : https://github.com/koajs/koa/wiki
 * Koa body parser  : https://github.com/dlau/koa-body#koa-body--
 * Koa better router: https://www.npmjs.com/package/@koa/router
 * Koa Cors         : https://www.npmjs.com/package/@koa/cors
 * Bunyan           : https://www.npmjs.com/package/bunyan
 * Koa guide        : https://github.com/koajs/koa/blob/master/docs/guide.md
 */
'use strict';
import Koa from 'koa';
import Cors from '@koa/cors';
import Helmet from 'koa-helmet';
import KoaBody from 'koa-body';
import Router from '@koa/router';

import log from './util/logger';
import {routerAdmin} from './api/v1/admin';
import {routerJWT} from './controller/jwt-examples';
import {requestLogger} from './middleware/request-logger';

const SERVER_PORT = Number(process.env.PORT) || 3100;
const SERVER_ADDRESS = '127.0.0.1';

// Handling shutdown graceful.
// Perform clean-up here.
process.on('SIGTERM', () => {
  log.error('SIGTERM signal received: shutting down HTTP server');
  log.error('HTTP server closed');
  process.exit(-1);
});
process.on('SIGHUP', () => {
  log.error('SIGHUP signal received: shutting down HTTP server');
  log.error('HTTP server closed');
  process.exit(-1);
});

const app = new Koa();
const router = new Router();

// Server logging.
app.context.log = log;

log.info(`NODE ENV: ${app.env}`);

/**
 * Setup middleware
 * Koa Cors         : https://www.npmjs.com/package/@koa/cors
 * Koa body parser  : https://github.com/dlau/koa-body#koa-body--
 * Koa better router: https://github.com/tunnckoCore/koa-better-router#koa-better-router---
 * Koa Helmet       : https://github.com/venables/koa-helmet
 */
app.use(Helmet());
app.use(Cors());
app.use(KoaBody());

/**
 * Logger middleware logs all incoming requests.
 * Writing middleware: https://expressjs.com/en/guide/writing-middleware.html
 * Using middleware  : https://expressjs.com/en/guide/using-middleware.html
 */
app.use(requestLogger);

/**
 * Setup Router middleware.
 */
app.use(routerAdmin.middleware());
app.use(router.middleware());
app.use(routerJWT.middleware());

// Log server error
app.on('error', (err, ctx) => {
  ctx.log.error(err, ctx);
});

router.get('/hello', async (ctx) => {
  ctx.body = 'Server is running';
});

router.get('/error/request', async (ctx) => {
  ctx.throw(405, 'Request error thrown');
});

router.get('/error/server', async (ctx) => {
  ctx.throw(505, 'Server error thrown');
});

/**
 * Start server
 * SERVER_ADDRESS: IP address to bind to.
 * SERVER_PORT: Port number to listen to requres.
 */
log.info('Server started');
const server = app.listen(SERVER_PORT, SERVER_ADDRESS, () => {
  process.stdout.write(
    `Server listening on ${SERVER_ADDRESS}:${SERVER_PORT}\n`,
  );
  log.info(`Server Listening on ${SERVER_ADDRESS}:${SERVER_PORT}`);
});

// Handling graceful shutdown.
// Perform clean-up here.
process.on('SIGTERM', () => {
  log.error('SIGTERM signal received: shutting down HTTP server');
  server.close(() => {
    log.error('HTTP server closed');
  });
});
