"use strict";
var utils = require("./task.utils");
var file = require("./file.utils");
var task_utils_1 = require("./task.utils");
var task_utils_2 = require("./task.utils");
var debug = require('debug')('cb:input');
var _ = require('../lodash.custom');
(function (InputTypes) {
    InputTypes[InputTypes["DefaultExternalFile"] = "DefaultExternalFile"] = "DefaultExternalFile";
    InputTypes[InputTypes["ExternalFile"] = "ExternalFile"] = "ExternalFile";
    InputTypes[InputTypes["InlineObject"] = "InlineObject"] = "InlineObject";
    InputTypes[InputTypes["CBFile"] = "CBFile"] = "CBFile";
    InputTypes[InputTypes["InlineJSON"] = "InlineJSON"] = "InlineJSON";
})(exports.InputTypes || (exports.InputTypes = {}));
var InputTypes = exports.InputTypes;
function getInputs(config, inlineInput) {
    /**
     * If the User provided a -c flag we MUST validate this
     * request first as it may fail and then we don't want to continue
     */
    if (config.input.length) {
        debug("config flag provided " + config.input);
        var stringInputs = config.input.filter(function (x) { return typeof x === 'string'; });
        var inlineInputs = config.input.filter(function (x) { return task_utils_2.isPlainObject(x); });
        var fileInputs = file.readInputFiles(stringInputs, config.cwd);
        var mergedFileInputs = fileInputs.valid.map(function (file) { return file.input; });
        var mergedInputs = _.merge.apply(_, [generateBaseInput({})].concat(mergedFileInputs, inlineInputs, [inlineInput]));
        if (fileInputs.invalid.length) {
            return {
                type: InputTypes.ExternalFile,
                errors: fileInputs.invalid.map(function (x) { return x.errors[0]; }),
                sources: fileInputs.invalid,
                inputs: [],
            };
        }
        return {
            type: InputTypes.ExternalFile,
            errors: [],
            sources: fileInputs.valid,
            inputs: [
                /**
                 * Merged all given configs into a single obj
                 * This is to allow, for example, production
                 * configuration to override dev etc..
                 */
                mergedInputs
            ],
        };
    }
    if (config.fromJson) {
        try {
            var parsed = JSON.parse(config.fromJson);
            return {
                errors: [],
                sources: [],
                type: InputTypes.InlineJSON,
                inputs: [generateBaseInput(parsed)]
            };
        }
        catch (e) {
            return {
                errors: [{ type: task_utils_1.InputErrorTypes.InvalidJson, json: config.fromJson, error: e }],
                sources: [],
                type: InputTypes.InlineJSON,
                inputs: []
            };
        }
    }
    /**
     * If the User provided --cbfile flag we MUST validate this
     * request first as it may fail and then we don't want to continue
     */
    if (config.cbfile) {
        debug("'cbfile' flag provided " + config.cbfile);
        var cbfiles = file.retrieveCBFiles(config);
        if (cbfiles.invalid.length) {
            return {
                type: InputTypes.CBFile,
                errors: cbfiles.invalid.map(function (x) { return x.errors[0]; }),
                sources: cbfiles.invalid,
                inputs: [],
            };
        }
        return {
            type: InputTypes.CBFile,
            errors: [],
            sources: cbfiles.valid,
            inputs: [],
        };
    }
    /**
     * Crossbow may be used with a simple object literal input.
     * This is how the test suit is even possible in such a system
     */
    if (utils.isPlainObject(inlineInput)) {
        debug("plain object given as input " + JSON.stringify(inlineInput));
        return {
            type: InputTypes.InlineObject,
            errors: [],
            sources: [],
            inputs: [generateBaseInput(inlineInput)]
        };
    }
    /**
     * Finally, try any cbfiles in the cwd
     */
    var defaultCbFiles = file.retrieveCBFiles(config);
    /**
     * If a cbfile.js **was** found in the current
     * directory, it will have been 'required' and therefor
     * some code will have run, which may of errored.
     * So here we check for that possible error by
     * filtering out `InputFileNotFound` errors (which simply mean
     * a cbfile.js was not found anyway.
     */
    var inputErrors = defaultCbFiles.invalid.filter(function (x) { return x.errors[0].type !== task_utils_1.InputErrorTypes.InputFileNotFound; });
    if (inputErrors.length) {
        return {
            type: InputTypes.CBFile,
            errors: inputErrors.map(function (x) { return x.errors[0]; }),
            sources: inputErrors,
            inputs: [],
        };
    }
    if (defaultCbFiles.valid.length) {
        debug("Default cbfile found " + defaultCbFiles.valid[0].resolved);
        return {
            errors: [],
            type: InputTypes.CBFile,
            sources: defaultCbFiles.valid,
            inputs: []
        };
    }
    /**
     * At this point, the user has not attempted to load any config files manually
     * so we try to load any defaults that are in the CWD
     */
    var defaultInputputFiles = file.retrieveDefaultInputFiles(config);
    if (defaultInputputFiles.valid.length) {
        debug("Default input found " + defaultInputputFiles.valid[0].resolved);
        return {
            errors: [],
            type: InputTypes.DefaultExternalFile,
            sources: defaultInputputFiles.valid,
            inputs: [generateBaseInput(defaultInputputFiles.valid[0].input)]
        };
    }
    /**
     * If we reach this point, we're working with
     * 1. NO external input files
     * 2. NO inline Object literal
     *
     * Which means we just need the stub objects, enough
     * to allow the system to work.
     */
    debug("No external input given/found, using default");
    return {
        errors: [],
        sources: [],
        type: InputTypes.InlineObject,
        inputs: [generateBaseInput({})]
    };
}
exports.getInputs = getInputs;
/**
 * `Input` is the object that is looked at to resolve tasks/options and
 * watchers
 */
function generateBaseInput(incoming) {
    return _.merge({
        tasks: {},
        watch: {
            before: [],
            options: {}
        },
        options: {},
        env: {}
    }, incoming || {});
}
exports.generateBaseInput = generateBaseInput;
//# sourceMappingURL=input.resolve.js.map