'use strict';

/**
 * Module dependencies.
 */
var fs = require('fs'),
    http = require('http'),
    https = require('https'),
    express = require('express'),
    morgan = require('morgan'),
    bodyParser = require('body-parser'),
    session = require('express-session'),
    compress = require('compression'),
    methodOverride = require('method-override'),
    cookieParser = require('cookie-parser'),
    helmet = require('helmet'),
    favicon = require('serve-favicon'),
    RedisStore = require('connect-redis')(session),
    config = require('./config'),
    consolidate = require('consolidate'),
    path = require('path'),
    _ = require('lodash'),
    log = require('./log');
var swigCache = {};
var swig = require('swig');
var numeral = require('numeral');
var cors = require('cors');

module.exports = function() {
    // Initialize express app
    var app = express();
    app.use(cors());

    app.use(favicon('./public/img/favicon1.ico'));

    // Globbing model files
    config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
        require(path.resolve(modelPath));
    });

    // Setting application local variables
    app.locals.title = config.app.title;
    app.locals.version = config.version;
    app.locals.description = config.app.description;
    app.locals.keywords = config.app.keywords;
    // app.set('subdomain offset', config.subdomain_offset);

    // Showing stack errors
    app.set('showStackError', true);

    // Set swig as the template engine
    app.engine('server.view.html', consolidate[config.templateEngine]);

    // Set views path and view engine
    app.set('view engine', 'server.view.html');
    app.set('views', ['./app/views']);

    // Environment dependent middleware
    var developMode;
    if (process.env.NODE_ENV === 'production') {
        app.locals.cache = 'memory';
        developMode = false;
        // Enable logger (morgan)
        app.use(morgan('short'));
    } else if (process.env.NODE_ENV !== 'test') {
        developMode = true;
        // Enable logger (morgan)
        app.use(morgan('dev'));
        // Disable views cache
        app.set('view cache', false);
    }

    // config swig template engine
    initSwig();

    // Request body parsing middleware should be above methodOverride
    app.use(bodyParser.urlencoded({
        extended: true,
        limit: '50mb'
    }));
    app.use(bodyParser.json({
        limit: '50mb'
    }));
    app.use(methodOverride());

    // CookieParser should be above session
    app.use(cookieParser());

    // Express MongoDB session storage
    if (process.env.NODE_ENV === 'secure') {
        var cookieSecure = true;
    } else {
        var cookieSecure = false;
    }
    app.use(session({
        saveUninitialized: true,
        resave: true,
        secret: config.sessionSecret,
        cookie: {
            secure: cookieSecure,
            httpOnly: true,
            maxAge: config.session_max_age
        },
        // store: new mongoStore({
        //     mongooseConnection: db,
        //     collection: config.sessionCollection
        // })
        store: new RedisStore()
    }));

    // Use helmet to secure Express headers
    app.use(helmet());
    app.disable('x-powered-by');

    // Should be placed before express.static
    app.use(compress({
        filter: function(req, res) {
            return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
        }
    }));

    // Setting the app router and static folder
    app.use(express.static(path.resolve('./public'), {
        maxAge: config.cache_max_age
    }));

    // Passing checking subdomain middleware
    app.use(checkSubDomain);

    // Globbing routing files
    config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
        require(path.resolve(routePath))(app);
    });

    // Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
    app.use(function(err, req, res, next) {
        logError(err, res, next);
    });
    // handle uncaught exception, return status code 500
    app.on('uncaughtException', function(req, res, route, err) {
        logError(err, res);
    });

    // Assume 404 since no middleware responded
    app.use(function(req, res) {
        res.status(404).render('404', {
            url: req.originalUrl,
            error: 'Not Found'
        });
    });

    // Log SSL usage
    console.log('Normal using http protocol port ' + config.port);

    var httpServer = http.createServer(app);

    // Return HTTPS server instance
    return httpServer;
};

function logError(err, res, next) {
    // If the error object doesn't exists
    if (!err && next) return next();

    log.error({
        code: Date.now(),
        reason: err.stack
    });

    // Error page
    res.status(500).render('500', {
        error: err.stack
    });
}

function initSwig(developMode) {
    swig.setFilter('currency', function(input) {
        return numeral(input).format('0,0');
    });
    swig.setDefaults({
        cache: {
            get: function(key) {
                return swigCache[key];
            },
            set: function(key, val) {
                if (key.indexOf('swig-no-cache-option') === -1) {
                    swigCache[key] = val;
                }
            }
        }
    });
    // get city name by code
    swig.setFilter('city_name', function(input) {
        var cities = require('../app/resources/provinces.json');
        var idx = _.findIndex(cities, function(c) {
            return c.code === input.toString()
        });
        if (idx > -1) return cities[idx].name;
        return '';
    });
}

/**
 * Middleware checking subdomain
 * @param  {[type]}   req  [description]
 * @param  {[type]}   res  [description]
 * @param  {Function} next [description]
 * @return {[type]}        [description]
 */
function checkSubDomain(req, res, next) {
    var hostUrl = req.headers.host;
    if (!hostUrl)
        hostUrl = req.get('host');
    res.locals.url = req.protocol + '://' + req.headers.host + req.url;
    // Invalid request, since headers.host should be set, most likely a malicious attempt
    if (!hostUrl) return res.status(400).send();
    hostUrl = hostUrl.replace(/^www\./, '').toLowerCase();
    var domain = hostUrl.split('.');
    var subdomains = req.subdomains || [];
    if (subdomains.length > 0 && subdomains[0] === 'www') {
        subdomains.splice(0, 1);
    }
    // lấy domain (sau khi bỏ subdomain)
    domain.splice(0, subdomains.length);
    req.subDomain = {
        host: hostUrl,
        domain: domain.join('.').split(':')[0],
        domainWithPort: domain.join('.'),
        hdvDomain: config.domain,
        having: subdomains.length > 0
    };
    req.subDomain.selfDomain = config.domain.split(':')[0] === req.subDomain.domain;
    req.subDomain.store_code = subdomains.length > 0 ? subdomains.join('.') : '';
    next();
}
