// Copyright (c) 2018 Dominic Masters
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

const
  http = require('http'),
  express = require('express'),
  bodyParser = require('body-parser'),
  fs = require('fs'),
  path = require('path'),
  webpack = require('webpack'),
  WebpackCompiler = require('./../webpack/WebpackCompiler'),
  API = require('./api/API')
;

const SERVE_FOLDER = path.resolve(`${__dirname}/../../dist`);

class Server {
  constructor(app) {
    this.app = app;

    //Server settings
    this.ip =
      app.getConfig().get("IP") ||
      app.getConfig().get("server.ip") ||
      process.env.ip ||
      process.env.IP ||
      null
    ;

    this.port =
      app.getConfig().get("PORT") ||
      app.getConfig().get("port") ||
      app.getConfig().get("server.port") ||
      process.env.port ||
      process.env.PORT ||
      80
    ;

    //Setup the express wrapper.
    this.express = express();

    //Setup Express Middleware
    this.express.use(bodyParser.json({
      type:'application/json' // to support JSON-encoded bodies
    }));

    this.express.use(bodyParser.urlencoded({
      extended: true
    }));

    //Serve Static Files
    this.express.use(express.static(SERVE_FOLDER));

    //Register API Handlers
    this.api = new API(this);
    this.api.loadHandlers();

    //Setup fallback GET request
    this.express.get('*', (req,res) => this.onGetRequest(req,res));

    //Setup our webpack compiler
    this.compiler = webpack(WebpackCompiler());
  }

  getExpress() {return this.express;}
  getApp() {return this.app;}
  getHTTP() {return this.http;}

  async init() {
    //Create our HTTP and (if needed HTTPS) server(s)
    this.http = http.createServer(this.express);
    this.http.on('error', e => this.onServerError(e));

    //Start the compiler watching
    this.watcher = this.compiler.watch({}, (e,s) => this.onWatchChange(e,s));

    //Start Listening
    this.http.listen({
      host: this.ip,
      port: this.port
    }, e => this.onServerStart(e));
  }

  //Events
  onServerStart(e) {
    this.boundAddress = this.http.address();
  }

  onServerError(e) {
    console.error('Error');
    console.error(e);
  }

  onGetRequest(req, res) {
    let file = path.resolve(`${SERVE_FOLDER}/index.html`);
    res.sendFile(file);
  }

  onWatchChange(error,stats) {
    if(error || (stats.compilation.errors && stats.compilation.errors.length)) {
      return this.app.error(error || stats.compilation.errors);
    }

    this.app.log("Server Compiled!");
  }
}

module.exports = Server;