import memoize from './memoize';

/**
 * Shorter and more simple implementation of reselect's createSelector
 * Takes one or more selectors, or an array of selectors, computes their values
 * and passes them as arguments to resultFunc.
 * @see https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc
 * @param {function} fns
 * @returns {function(...[*]=)}
 * @throws TypeError If any of the arguments is not a function
 */
export default function createSelector(...fns) {
    // skip calling the result function when the params are unchanged (saving expensive calculation)
    const resultFunc = fns.pop();
    if (typeof resultFunc !== 'function') {
        throw new TypeError('createSelector accepts only function as argument!');
    }
    const memResultFunc = memoize(resultFunc);
    // check dependency functions
    const length = fns.length;
    for (let i = 0; i < length; i++) {
        const fn = fns[i];
        if (typeof fn !== 'function') {
            throw new TypeError('All of the dependencies have to be a function!');
        }
    }

    // memoize will skip the recalculation if the selector function is called with the same arguments
    // (like an unchanged state object)
    return memoize((...args) => {
        // get the result of the dependency functions
        const params = [];
        for (let i = 0; i < length; i++) {
            params.push(fns[i].apply(null, args));
        }
        // call the result function with the params
        return memResultFunc.apply(null, params);
    });
}
