'use strict';

//
// IMPORTANT !!!
//
// None of this is authenticated or encrypted
//

module.exports.create = function (app, xconfx, models) {
  var PromiseA = require('bluebird');
  var path = require('path');
  var fs = PromiseA.promisifyAll(require('fs'));
  var dns = PromiseA.promisifyAll(require('dns'));

  function isInitialized () {
    // TODO read from file only, not db
    return models.ComDaplieWalnutConfig.get('config').then(function (conf) {
      if (!conf || !conf.primaryDomain/* || !conf.primaryEmail*/) {
        console.log('[DEBUG] uninitialized or incomplete config:', JSON.stringify(conf));
        return false;
      }

      xconfx.primaryDomain = xconfx.primaryDomain || conf.primaryDomain;
      // backwards compat for something or other
      return true;
    });
  }

  function initialize() {
    var express = require('express');
    var getIpAddresses = require('./ip-checker').getExternalAddresses;
    var resolveInit;

    function getConfig(req, res) {
      getIpAddresses().then(function (inets) {
        var results = {
          hostname: require('os').hostname()
        , inets: inets.addresses.map(function (a) {
            a.time = undefined;
            return a;
          })
        };
        //res.send({ inets: require('os').networkInterfaces() });
        res.send(results);
      });
    }

    function verifyIps(inets, hostname) {
      var map = {};
      var arr = [];

      inets.forEach(function (addr) {
        if (!map[addr.family]) {
          map[addr.family] = true;
          if (4 === addr.family) {
            arr.push(dns.resolve4Async(hostname).then(function (arr) {
              return arr;
            }, function (/*err*/) {
              return [];
            }));
          }
          if (6 === addr.family) {
            arr.push(dns.resolve6Async(hostname).then(function (arr) {
              return arr;
            }, function (/*err*/) {
              return [];
            }));
          }
        }
      });

      return PromiseA.all(arr).then(function (fams) {
        console.log('DEBUG hostname', hostname);
        var ips = [];

        fams.forEach(function (addrs) {
          console.log('DEBUG ipv46');
          console.log(addrs);
          addrs.forEach(function (addr) {
            inets.forEach(function (a) {
              if (a.address === addr) {
                a.time = undefined;
                ips.push(a);
              }
            });
          });
          console.log('');
        });

        return ips;
      });
    }

    function setConfig(req, res) {
      return PromiseA.resolve().then(function () {
        // TODO expect authenticated oauth3 user
        var config = req.body;
        var safeConfig = {};

        if ('string' !== typeof config.domain) {
          return PromiseA.reject(new Error("'domain' should be a string specifying a valid domain name"));
        }

        config.domain = (config.domain||'').replace(/^www\./, '');

        // TODO url-testing lib
        if (!/\w+\.\w+/.test(config.domain)) {
          return PromiseA.reject(new Error("'domain' should be a string specifying a valid domain name"));
        }


        var configpath = path.join(__dirname, '..', '..', 'config', config.domain + '.json');
        safeConfig = { primaryDomain: config.domain };
        xconfx.primaryDomain = safeConfig.primaryDomain;
        return fs.writeFileAsync(configpath, JSON.stringify(safeConfig, null, '  '), 'utf8').then(function () {
          // TODO nix SQL
          return models.ComDaplieWalnutConfig.upsert('config', safeConfig);
        });
      }).then(function () {
        if (resolveInit) {
          resolveInit();
          resolveInit = null;
        }
        res.send({ success: true });
      }, function (err) {
        console.error('Error lib/bootstrap.js');
        console.error(err.stack || err);
        res.send({ error: { message: err.message || err.toString() } });
      });
    }

    var CORS = require('connect-cors');
    var cors = CORS({ credentials: true, headers: [
      'X-Requested-With'
    , 'X-HTTP-Method-Override'
    , 'Content-Type'
    , 'Accept'
    , 'Authorization'
    ], methods: [ "GET", "POST", "PATCH", "PUT", "DELETE" ] });

    app.use('/', function (req, res, next) {
      console.log('[lib/bootstrap.js] req.url', req.url);

      return isInitialized().then(function (initialized) {
        if (!initialized) {
          next();
          return;
        }

        // init is always considered to be
        resolveInit(true);

        // TODO feed this request back through the route stack from the top to avoid forced refresh?
        res.statusCode = 302;
        res.setHeader('Location', req.url);
        res.end("<!-- App bootstraping complete, but you got here somehow anyway. Let's redirect you so you get to the main app. -->");
      });
    });

    // NOTE Allows CORS access to API with ?access_token=
    // TODO Access-Control-Max-Age: 600
    // TODO How can we help apps handle this? token?
    // TODO allow apps to configure trustedDomains, auth, etc
    app.use('/api', cors);
    app.get('/api/walnut@daplie.com/init', getConfig);
    app.get('/api/com.daplie.walnut.init', getConfig); // deprecated
    app.post('/api/walnut@daplie.com/init', setConfig);
    app.post('/api/com.daplie.walnut.init', setConfig); // deprecated

    // TODO use package loader
    //app.use('/', express.static(path.join(__dirname, '..', '..', 'packages', 'pages', 'walnut@daplie.com', 'init')));
    app.use('/', express.static(path.join(__dirname, 'walnut@daplie.com', 'init')));
    app.use('/', function (req, res, next) {
      res.statusCode = 404;
      res.end('Walnut Bootstrap Not Found. Mising walnut@daplie.com/init');
    });

    return new PromiseA(function (_resolve) {
      resolveInit = _resolve;
    });
  }

  return isInitialized().then(function (initialized) {
    if (initialized) {
      return true;
    }

    return initialize();
  }, function (err) {
    console.error('FATAL ERROR:');
    console.error(err.stack || err);
    app.use('/', function (req, res) {
      res.send({
        error: {
          message: "Unrecoverable Error Requires manual server update: " + (err.message || err.toString())
        }
      });
    });
  });
};
