import { memoize } from './memoize.esnext';
import { isEqual } from './isEqual.esnext';

const MAX_CACHE_SIZE = 50;
const MEMOIZE_OPTIONS = {
  equalityCheck: isEqual,
  maxSize: MAX_CACHE_SIZE
};
// eslint-disable-next-line func-style
const when = function when(conditions, value) {
  const config = isConditionalStyle(this) ? {
    default: this.default,
    conditionals: [...this.conditionals, {
      conditions,
      value
    }]
  } : {
    conditionals: [{
      conditions,
      value
    }]
  };
  return createChainableConditionalStyle(config);
};

// This interface is only used to provide documentation for the Style helper.
// It is not used in the implementation.
/** @publicDocs */

/**
 * Style is a helper for authoring conditional values for prop styles.
 * Write complex conditional styles based on one or more conditions (viewport
 * sizes and interactive states) in a concise and expressive way.
 */
const Style = {
  /**
   * Sets an optional default value to use when no other condition is met.
   *
   * @param defaultValue The default value
   * @returns The chainable condition style
   */
  default: memoize(defaultValue => createChainableConditionalStyle({
    default: defaultValue,
    conditionals: []
  }), MEMOIZE_OPTIONS),
  /**
   * Adjusts the style based on different conditions. All conditions, expressed
   * as a literal object, must be met for the associated value to be applied.
   *
   * The `when` method can be chained together to build more complex styles.
   *
   * @param conditions The condition(s)
   * @param value The conditional value that can be applied if the conditions are met
   * @returns The chainable condition style
   */
  when: memoize(when, MEMOIZE_OPTIONS)
};
function createChainableConditionalStyle(conditionalStyle) {
  const proto = {};
  const returnConditionalStyle = Object.create(proto);
  Object.assign(returnConditionalStyle, conditionalStyle);
  proto.when = memoize(when.bind(returnConditionalStyle), MEMOIZE_OPTIONS);
  return returnConditionalStyle;
}
function isConditionalStyle(value) {
  return value !== null && typeof value === 'object' && 'conditionals' in value;
}
function isConditionalStyleWithDefault(value) {
  return isConditionalStyle(value) && 'default' in value && value.default !== undefined;
}

export { Style, isConditionalStyle, isConditionalStyleWithDefault };
