'use strict';

var expressionTypes = require('./expression-types.cjs');
var strings = require('./strings.cjs');

/**
 * Throw an error with a descriptive message
 * @param   { string } message - error message
 * @param   { string } cause - optional error cause object
 * @returns { undefined } hoppla... at this point the program should stop working
 */
function panic(message, cause) {
  throw new Error(message, { cause })
}
/**
 * Returns the memoized (cached) function.
 * // borrowed from https://www.30secondsofcode.org/js/s/memoize
 * @param {Function} fn - function to memoize
 * @returns {Function} memoize function
 */
function memoize(fn) {
  const cache = new Map();
  const cached = (val) => {
    return cache.has(val)
      ? cache.get(val)
      : cache.set(val, fn.call(this, val)) && cache.get(val)
  };
  cached.cache = cache;
  return cached
}

/**
 * Generate key-value pairs from a list of attributes
 * @param   {Array} attributes - list of attributes generated by the riot compiler, each containing type, name, and evaluate function
 * @param   {object} scope - the scope in which the attribute values will be evaluated
 * @returns {object} An object containing key-value pairs representing the computed attribute values
 */
function generatePropsFromAttributes(attributes, scope) {
  return attributes.reduce((acc, { type, name, evaluate }) => {
    const value = evaluate(scope);

    switch (true) {
      // spread attribute
      case !name && type === expressionTypes.ATTRIBUTE:
        return {
          ...acc,
          ...value,
        }
      // ref attribute
      case type === expressionTypes.REF:
        acc.ref = value;
        break
      // value attribute
      case type === expressionTypes.VALUE:
        acc.value = value;
        break
      // normal attributes
      default:
        acc[strings.dashToCamelCase(name)] = value;
    }

    return acc
  }, {})
}

exports.generatePropsFromAttributes = generatePropsFromAttributes;
exports.memoize = memoize;
exports.panic = panic;
