/**
 * Created by tdzl2_000 on 2015-12-18.
 */

import { doAction, applyFilter } from './filter';
import { SESSION } from './session';
import { initPlugins } from './plugins';
import { getStorage } from './objects';
import Koa from 'koa';
import UCMSError from './UCMSError';
import Router from 'koa-router';
import bodyParser from 'koa-bodyparser';

const INIT = 'server.init';
const INIT_ROUTE = 'server.initRoute.';
const WILL_LISTEN = 'server.willListen';
const DID_LISTEN = 'server.didListen';

export const SERVER = {
  INIT,
  INIT_ROUTE,
  WILL_LISTEN,
  DID_LISTEN,
};

export async function startServer(port, host) {
  // Load plugins
  await initPlugins();

  // init and get storage;
  getStorage();

  // Create app
  const app = new Koa();
  await doAction(INIT, app);

  app.use(bodyParser());

  // Translate error into json respnose.
  app.use((ctx, next) => {
    if (__DEV__) {
      console.log(ctx.url, ctx.request.body);
    }
    return next()
      .then(() => {
        if (__DEV__) {
          console.log(ctx.body);
        }
        ctx.body = ctx.body || { ok: 1 };
        ctx.body.ok = 1;
      }, err => {
        if (__DEV__) {
          console.error(err.stack);
        }
        ctx.body = {
          message: err.message,
        };
        ctx.status = (err instanceof UCMSError) ? err.code : 500;
      });
  });

  // Parse session data.
  app.use(async (ctx, next) => {
    const token = await applyFilter(SESSION.LOAD_TOKEN, ctx);
    if (token) {
      const session = await applyFilter(SESSION.LOAD, token);
      ctx.session = session;
    }
    await next();
  });

  const router = new Router();
  await doAction(INIT_ROUTE + '/', router);
  app.use(router.routes());

  // Treat 404 as Invalid API error.
  app.use(() => Promise.reject(new UCMSError(404, 'Invalid API')));

  // Start port listening
  await doAction(WILL_LISTEN, app);
  await new Promise((res, rej) => {
    const server = app.listen(port, host, res);
    server.on('error', rej);
  });
  await doAction(DID_LISTEN, app);
  console.log('Ready.');
}
