const { isValidLevel } = require('../helpers/validate'),
    { ERROR, WARN, INFO } = require('../constants/level'),
    Collector = require('../collectors/AbstractCollector');

/**
 * @class Originator
 * @description This holds the basic details of an originator
 *
 */
class Originator {
    /**
     * @method constructor
     * @description It initialize the necessary props for originator
     * @param {[Object={}]} options
     * @param {String=} options.level
     * @param {String=} options.sessionId
     * @param {String=} options.origin
     * @param {Array=} options.collectors
     * @throws InvalidParamsException
     */
    constructor (options = {}) {

        // Thrown error if the options is not of type object
        if (typeof options !== 'object' || Array.isArray(options)) {
            throw new Error('InvalidParamException: options should be of type Object');
        }

        this.sessionId = options.sessionId || Date.now();

        this.origin = options.origin || 'Unknown Origin';

        this.collectors = options.collectors || [];

        // Set the level
        this.level = isValidLevel(options.level) ? options.level : INFO;
    }

    /**
     * @description Switches the log level
     * Useful when debugging internally or externally
     *
     * @param {String} level should be among the valid log levels
     */
    setLogLevel (level) {
        if (isValidLevel(level) === false) { return; }
        this.level = level;
        this.collectors.forEach((collector) => {
            collector.setLogLevel(this.level);
        });
    }

    /**
     * @private
     * @method _log
     * @description It calls the log function of all the collectors with the level and sanitized message
     * @param {[String]} level
     * @param {Array = []} messages
     */
    _log (level, messages) {
        this.collectors.forEach((collector) => {
            collector.log(
                level,
                {
                    sessionId: this.sessionId,
                    timestamp: Date.now(),
                    origin: this.origin,
                    messages
                }
            );
        });
    }

    // eslint-disable-next-line jsdoc/check-param-names
    /**
     * @method error
     * @description It calls the _log with level ERROR
     * @param {...*}
     */
    error (...args) {
        this._log(ERROR, args);
    }

    // eslint-disable-next-line jsdoc/check-param-names
    /**
     * @method warn
     * @description It calls the _log with level WARN
     * @param {...*}
     */
    warn (...args) {
        this._log(WARN, args);
    }

    // eslint-disable-next-line jsdoc/check-param-names
    /**
     * @method info
     * @description It calls the _log with default level INFO
     * @param {...*}
     */
    info (...args) {
        this._log(INFO, args);
    }

    /**
     * @method addCollector
     * @description It adds the collector to the collectors we have
     * @param {Collector} collector
     * @throws InvalidParamException
     */
    addCollector (collector) {
        // Thrown error if the collector is not of type Collector
        if (!(collector instanceof Collector)) {
            throw new Error('InvalidParamException: collector of type Collector');
        }

        this.collectors.push(collector);
    }

    /**
     * @method getContext
     * @description Generates a context object, it can be attached to the log event. Must be present for NewRelic logger
     * @param  {String} api - Name of the component
     * @param  {String} domain - Name of the team which owns the component
     */
    // eslint-disable-next-line class-methods-use-this
    getContext (api, domain) {
        return {
            api,
            domain
        };
    }
}

module.exports = Originator;
