'use strict';

var minimist = require('minimist');
var fs = require('fs');
var $ = require('gulp-load-plugins')();
var gulp = require('gulp');
var _ = require('lodash');
var globalTunnel = require('global-tunnel');
var expand = require('glob-expand');

////////////////////////////////////////
// 1. Get build-id and config parameters
////////////////////////////////////////
var knownOptions = {
    string: [ 'build-id', 'config', 'specs' ],
    default: {
        'build-id': process.env.CELLSTORE_BUILD_ID !== undefined ? process.env.CELLSTORE_BUILD_ID : process.env.RANDOM_ID,
        'config': ( process.env.CIRCLE_BRANCH !== undefined && fs.existsSync('config/' + process.env.CIRCLE_BRANCH + '.json.enc') ) ? process.env.CIRCLE_BRANCH : process.env.CELLSTORE_CONFIG
    }
};

var args = minimist(process.argv.slice(2), knownOptions);
var buildId = args['build-id'];
if(buildId === undefined || buildId === ''){
    var msg = 'no buildId available. ' + $.util.colors.red('Command line argument --build-id missing.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

var configId = args.config;
if(configId === undefined || configId === ''){
    var msg = 'no configId available. ' + $.util.colors.red('Command line argument --config or env variable CELLSTORE_CONFIG missing.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

////////////////////////////////////////
// 2. Check if the config file is available
////////////////////////////////////////
var unencryptedConfigFile = 'config/' + configId + '.json';
var encryptedConfigFile = unencryptedConfigFile + '.enc';
if(!fs.existsSync(encryptedConfigFile) && !_.find(args._, function(target){ return target === 'encrypt'; })){
    var msg = 'Invalid --config command line argument. ' + $.util.colors.red('Config file ' + encryptedConfigFile + ' does not exist.');
    $.util.log(msg);
    throw new $.util.PluginError(__filename, msg);
}

////////////////////////////////////////
// 3. Are we in deploying for testing or to production?
////////////////////////////////////////
var isOnTravis = process.env.CIRCLECI === 'true';
var isOnTravisAndMaster = isOnTravis && process.env.CI_PULL_REQUEST === '' && process.env.CIRCLE_BRANCH === 'master';
// if a config/<branch>.json.enc exists we are on a production deployment branch
var isProd = fs.existsSync('config/' + process.env.CIRCLE_BRANCH + '.json.enc');
var isOnTravisAndProd = isOnTravis && isProd && process.env.CI_PULL_REQUEST === '';

if(isOnTravisAndProd && process.env.CIRCLE_BRANCH !== configId){
    $.util.log('We are on Travis and on a Production branch.');
    $.util.log('Current production branch "' + process.env.CIRCLE_BRANCH + '" doesn\'t match cellstore configuration "' + configId + '"');
    $.util.log($.util.colors.green('Nothing to do!'));
    process.exit(0);
}

////////////////////////////////////////
// 4. Setting up the test suite
////////////////////////////////////////
var specs = expand('tests/e2e/' + configId + '/*-scenario.js');
specs = _.union(specs, expand('tests/e2e/_all/*-scenario.js'));
//var specs = ['tests/e2e/_all/auth-scenario.js'];
// allow running single protractor specs using --specs arg
if (_.isString(args.specs) ){
    specs = args.specs.split(',');
}

////////////////////////////////////////
// 5. Initialize Config variable
////////////////////////////////////////
var config =
{
    isOnTravis: isOnTravis,
    isOnProduction: isOnTravisAndProd,
    isOnMaster: isOnTravisAndMaster,
    buildId: buildId,
    configId: configId,
    bucketName: '',
    projectName: '',
    portalAPIUrl: '',
    websiteUrl: '',
    paths: {
        //src and build folders
        app: 'app',
        dist: 'dist',
        tmp: '.tmp',
        queries: 'queries',

        //Reports
        reports: 'data/reports/' + configId + '/*.json',

        //Elastic Search meta data
        elasticSearchMapping: 'data/elastic-search/' + configId + '/mapping.json',

        //Static Assets
        json: ['*.json', 'tasks/templates/*.json.mustache', 'swagger/*.json', 'data/**/*.json', 'documentation/**/*.json' ],
        js: ['app/**/*.js'],
        css: ['app/**/*.css'],
        index: 'app/*.html',
        html: ['app/**/*.html'],
        images: 'app/images/**/*.{gif,jpg,png}',
        svgs: 'app/images/**/*.svg',
        sass: ['app/**/*.scss'],
        fonts: ['app/**/*.ttf', 'app/**/*.woff'],

        //CI
        tasks: ['gulpfile.js', 'tasks/*.js'],
        dependencies: ['./bower.json', './package.json'],

        //Crypted config
        encryptedConfigFile: encryptedConfigFile,
        unencryptedConfigFile: unencryptedConfigFile,

        //Queries
        jsoniq: ['queries/**/*.xq', 'queries/**/*.jq'],
        initQueries: [
            'queries/private/InitAuditCollection.jq',
            'queries/private/init.jq',
            [
                'queries/private/UpdateReportSchema.jq',
                'queries/private/cleanupTestUserReports.jq'
            ],
            'queries/private/initElasticSearch.jq'
        ],
        apiTestQueries: [
            'queries/public/test/**/*.jq'
        ],

        //Documentation
        documentation: 'documentation/**/*.md',

        //tests
        protractorConfigLocal: 'tests/e2e/config/protractor-conf.js',
        protractorConfigTravis: 'tests/e2e/config/protractor-travis-nosaucelabs-conf.js',
        e2eSpecs: specs,
        e2eReportsDir: '/tmp/e2e-reports'
    },
    credentials: {},
    '$28': undefined
};

var loadRawCredentials = function(config){
    $.util.log('loading credentials from: ' + config.paths.unencryptedConfigFile);
    var rawCredentials = JSON.parse(fs.readFileSync(config.paths.unencryptedConfigFile, 'utf-8'));
    config.rawCredentials = rawCredentials.all;
    var datasources = rawCredentials.all['28-datasources'];
    // fill up/overwrite with either prod or dev credentials
    if(config.isOnProduction){
        _.extend(config.rawCredentials, rawCredentials.prod);
    } else {
        _.extend(config.rawCredentials, rawCredentials.dev);
    }
    config.rawCredentials['28-datasources'] = _.union(config.rawCredentials['28-datasources'], datasources);
    _.defaults(config.rawCredentials, {
        's3-region': 'us-east-1',
        's3-protocol': 'https',
        '28-portal-protocol': 'http',
        '28-portal-project': 'portal',
        '28-portal-domain': '28.io',
        '28-portal-api-prefix': '/api',
        'cellstore-protocol': 'http'
    });
};

gulp.task('config:load', ['crypt:decrypt'], function(done){
    if(!_.isEmpty(config.credentials)){
        done();
        return;
    }

    loadRawCredentials(config);

    var src = fs.readFileSync('tasks/templates/config.json.template', 'utf-8');
    config.credentials = JSON.parse(_.template(src)({ credentials: config.rawCredentials }));
    config.bucketName = config.isOnProduction ? config.credentials.s3.bucketPrefix : config.credentials.s3.bucketPrefix + '-' + config.buildId;
    config.projectName = config.isOnProduction ? config.credentials['28'].projectPrefix : config.credentials['28'].projectPrefix + '-' + buildId;

    // where to deploy the cellstore?
    config.portalAPIUrl =
        _.template('<%= portalProtocol %>://<%= portalProject %>.<%= portalDomain %><%= portalApiPrefix %>')(config.credentials['28']);
    config.websiteUrl =
        _.template('http://<%= bucketName %>.s3-website-<%= credentials.s3.region %>.amazonaws.com')(config);

    $.util.log('Portal: ' + $.util.colors.green(config.portalAPIUrl));
    $.util.log('Bucket: ' + $.util.colors.green(config.bucketName));
    $.util.log('Project: ' + $.util.colors.green(config.projectName));
    $.util.log('Profile: ' + $.util.colors.green(config.credentials.cellstore.profile));

    if(_.isObject(config.credentials.http) && _.isString(config.credentials.http.proxy) && config.credentials.http.proxy !== ''){
        var proxy = config.credentials.http.proxy;
        var hostAndPort = proxy.substring(proxy.indexOf('//') + '//'.length).split(':');
        $.util.log('Setting up global proxy tunnel.');
        globalTunnel.initialize({
            'host': hostAndPort[0],
            'port': parseInt(hostAndPort[1])
        });
    }

    config.$28 = new (require('28').$28)(config.portalAPIUrl);
    done();
});

gulp.task('config', ['config:load', 'templates:create']);

module.exports = config;
