var chalk = require('chalk');
var Q = require('q');
var promptly = require('promptly');
var createError = require('../util/createError');

function JsonRenderer() {
    this._nrLogs = 0;
}

JsonRenderer.prototype.end = function(data) {
    if (this._nrLogs) {
        process.stderr.write(']\n');
    }

    if (data) {
        process.stdout.write(this._stringify(data) + '\n');
    }
};

JsonRenderer.prototype.error = function(err) {
    var message = err.message;
    var stack;

    err.id = err.code || 'error';
    err.level = 'error';
    err.data = err.data || {};

    // Need to set message again because it is
    // not enumerable in some cases
    delete err.message;
    err.message = message;

    // Stack
    stack = err.fstream_stack || err.stack || 'N/A';
    err.stacktrace = Array.isArray(stack) ? stack.join('\n') : stack;

    this.log(err);
    this.end();
};

JsonRenderer.prototype.log = function(log) {
    if (!this._nrLogs) {
        process.stderr.write('[');
    } else {
        process.stderr.write(', ');
    }

    process.stderr.write(this._stringify(log));
    this._nrLogs++;
};

JsonRenderer.prototype.prompt = function(prompts) {
    var promise = Q.resolve();
    var answers = {};
    var that = this;

    prompts.forEach(function(prompt) {
        var opts;
        var funcName;

        // Strip colors
        prompt.message = chalk.stripColor(prompt.message);

        // Prompt
        opts = {
            silent: true, // To not mess with JSON output
            trim: false, // To allow " " to not assume the default value
            default: prompt.default == null ? '' : prompt.default, // If default is null, make it '' so that it does not retry
            validator: !prompt.validate
                ? null
                : function(value) {
                      var ret = prompt.validate(value);

                      if (typeof ret === 'string') {
                          throw ret;
                      }

                      return value;
                  }
        };

        // For now only "input", "confirm" and "password" are supported
        switch (prompt.type) {
            case 'input':
                funcName = 'prompt';
                break;
            case 'confirm':
            case 'password':
                funcName = prompt.type;
                break;
            case 'checkbox':
                funcName = 'prompt';
                break;
            default:
                promise = promise.then(function() {
                    throw createError('Unknown prompt type', 'ENOTSUP');
                });
                return;
        }

        promise = promise.then(function() {
            // Log
            prompt.level = 'prompt';
            that.log(prompt);

            return Q.nfcall(promptly[funcName], '', opts).then(function(
                answer
            ) {
                answers[prompt.name] = answer;
            });
        });

        if (prompt.type === 'checkbox') {
            promise = promise.then(function() {
                answers[prompt.name] = answers[prompt.name].split(',');
            });
        }
    });

    return promise.then(function() {
        return answers;
    });
};

// -------------------------

JsonRenderer.prototype._stringify = function(log) {
    // To json
    var str = JSON.stringify(log, null, '  ');
    // Remove colors in case some log has colors..
    str = chalk.stripColor(str);

    return str;
};

module.exports = JsonRenderer;
