'use strict';

var async = require('async');

// from apps.js DO NOT UPDATE WHEN apps.js changes, as this is part of db migration!!
function postProcess(result) {
    try {
        result.manifest = JSON.parse(result.manifestJson);
        delete result.manifestJson;

        result.oldConfig = JSON.parse(result.oldConfigJson);
        delete result.oldConfigJson;

        result.portBindings = { };
        var hostPorts = result.hostPorts === null ? [ ] : result.hostPorts.split(',');
        var environmentVariables = result.environmentVariables === null ? [ ] : result.environmentVariables.split(',');

        delete result.hostPorts;
        delete result.environmentVariables;

        for (var i = 0; i < environmentVariables.length; i++) {
            result.portBindings[environmentVariables[i]] = parseInt(hostPorts[i], 10);
        }

        result.accessRestriction = JSON.parse(result.accessRestrictionJson);
        if (result.accessRestriction && !result.accessRestriction.users) result.accessRestriction.users = [];
        delete result.accessRestrictionJson;

        // TODO remove later once all apps have this attribute
        result.xFrameOptions = result.xFrameOptions || 'SAMEORIGIN';

        result.sso = !!result.sso; // make it bool

        result.debugMode = JSON.parse(result.debugModeJson);
        delete result.debugModeJson;
    } catch (e) {
        console.error('Failed to get restoreConfig for app.', e);
        console.error('Falling back to empty values to make the update succeed.');
        result.manifest = null;
    }
}

// from apps.js DO NOT UPDATE WHEN apps.js changes, as this is part of db migration!!
var APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationState', 'apps.installationProgress', 'apps.runState',
    'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.httpPort', 'apps.location', 'apps.dnsRecordId',
    'apps.accessRestrictionJson', 'apps.lastBackupId', 'apps.oldConfigJson', 'apps.memoryLimit', 'apps.altDomain',
    'apps.xFrameOptions', 'apps.sso', 'apps.debugModeJson' ].join(',');

exports.up = function(db, callback) {
    async.series([
        db.runSql.bind(db, 'ALTER TABLE backups ADD COLUMN restoreConfigJson TEXT'),
        // fill all the backups with restoreConfigs from current apps
        function addRestoreConfigs(callback) {
            console.log('Importing restoreConfigs');

            var appQuery = 'SELECT ' + APPS_FIELDS_PREFIXED + ',' +
                'GROUP_CONCAT(CAST(appPortBindings.hostPort AS CHAR(6))) AS hostPorts, GROUP_CONCAT(appPortBindings.environmentVariable) AS environmentVariables' +
                ' FROM apps LEFT OUTER JOIN appPortBindings ON apps.id = appPortBindings.appId' +
                ' GROUP BY apps.id ORDER BY apps.id';

            db.all(appQuery, function (error, apps) {
                if (error) return callback(error);

                apps.forEach(postProcess);

                async.eachSeries(apps, function (app, next) {
                    if (app.manifest === null) return next();

                    db.all('SELECT * FROM backups WHERE type="app" AND id LIKE "%app%\\_' + app.id + '\\_%"', function (error, backups) {
                        if (error) return next(error);

                        // from apps.js:getAppConfig()
                        var restoreConfig = {
                            manifest: app.manifest,
                            location: app.location,
                            accessRestriction: app.accessRestriction,
                            portBindings: app.portBindings,
                            memoryLimit: app.memoryLimit,
                            xFrameOptions: app.xFrameOptions || 'SAMEORIGIN',
                            altDomain: app.altDomain
                        };

                        async.eachSeries(backups, function (backup, next) {
                            db.runSql('UPDATE backups SET restoreConfigJson=?,creationTime=creationTime WHERE id=?', [ JSON.stringify(restoreConfig), backup.id ], next);
                        }, next);
                    });
                }, callback);
            });
        }
    ], callback);
};

exports.down = function(db, callback) {
    db.runSql('ALTER TABLE backups DROP COLUMN restoreConfigJson', callback);
};
