import classnames from 'classnames';
import utilClasses from "../../styles/utility.module.scss";
import customizable from './customizable';
const mapClassName = function mapClassName(cnArgs, classMap, options = {}) {
  const {
    strict = false,
    customizable: customizableClasses = []
  } = options;
  const handles = new Set(customizable(...customizableClasses).split(' '));
  const mapped = classnames(...cnArgs).split(' ').map(name => {
    if (classMap[name]) return classMap[name];
    if (handles.has(name)) return name;
    if (!strict) return name;
    return null;
  });
  return classnames(mapped);
};
export const merge = function merge(customClasses, options = {}) {
  const {
    strict = true,
    ...restOptions
  } = options;
  const allClasses = {
    ...utilClasses,
    ...customClasses
  };
  return (...args) => mapClassName(args, allClasses, {
    strict,
    ...restOptions
  });
};

/**
 * This is a custom wrapper around the `classnames` function that supports
 * a standard set of utility classes and provides a few additional niceties.
 * First it will pass all of its arguments to the `classnames` function to
 * resolve any conditional classes, classes that are set in arrays, and more.
 * Next it considers each individual class. If it is the name of a utility
 * class, the class gets mapped to the corresponding utility class; otherwise
 * the class is included as-is by default. See below for more on utility
 * classes.
 *
 * In addition to calling `cx(...args)` directly, you can use the associated
 * method `cx.strict(...args)`, which behaves just like the `cx(...args)`
 * function except for the fact that non-utility classes are ignored. This can
 * be useful if you _only_ care about utility classes and want some additional
 * protection against malformed utility classes. For instance, if you're
 * generating a classname like `bg-${myColor}` and `myColor` might be
 * undefined, then `cx.strict()` will ignore the malformed class
 * `bg-undefined`, because that's not a valid utility class.
 *
 * ```js
 * const className = `bg-${myColor}`; // myColor might be undefined
 * cx.strict(className); // --> ''
 * ```
 *
 * Finally, you can first call the associated factory method
 * `cx.merge(customClasses)`, which allows you to merge your own custom classes
 * with the set of built-in utility classes and returns a classname function
 * that behaves like `cx.strict()`. If you want to allow unknown classes to be
 * included you can pass a second argument `{ strict: false }` to `cx.merge()`;
 * that will cause the returned function to include unknown classes.
 *
 * ### Utility classes
 *
 * These are the built-in utility classes supported by `cx`. In the following
 * descriptions `${spacer}` is any valid spacing level (e.g., `"4"` for
 * `$spacing-4`), `${neutral}` is any of our neutral color names (e.g.,
 * `"gray-20"`) or `black` or `white` or `transparent`, and `${shadow}` is any
 * of our shadow levels.
 *
 * - `p-${spacer}` sets the padding of all four sides to the corresponding
 *   spacing level.
 * - `pt-${spacer}`, `pr-${spacer}`, `pb-${spacer}`, and `pl-${spacer}` set the
 *   top, right, bottom, or left padding to the corresponding spacing level,
 *   respectively.
 * - `px-${spacer}` and `py-${spacer}` set the horizontal (left and right) or
 *   vertical (top and bottom) padding to the corresponding spacing level,
 *   respectively.
 * - `m-${spacer}` sets the margins of all four sides to the corresponding
 *   spacing level.
 * - `mt-${spacer}`, `mr-${spacer}`, `mb-${spacer}`, and `ml-${spacer}` set the
 *   top, right, bottom, or left margin to the corresponding spacing level,
 *   respectively.
 * - `mx-${spacer}` and `my-${spacer}` set the horizontal (left and right) or
 *   vertical (top and bottom) margin to the corresponding spacing level,
 *   respectively.
 * - `edge-${spacer}` sets the border radius to the corresponding spacing
 *   level.
 * - `edge-round` sets the border radius to `$spacing-4`.
 * - `edge-sharp` sets the border radius to zero.
 * - `edge-max` sets the border radius to `100vmax`, which should always
 *   provide a fully rounded cap.
 * - `bg-${neutral}` sets the background color to the corresponding neutral
 *   color.
 * - `fg-${neutral}` sets the foreground color to the corresponding neutral
 *   color.
 * - `fgc-${neutral}` sets the foreground color to the contrast color (black or
 *   white) for the corresponding neutral color.
 * - `bgc-${neutral}` sets the background color to the corresponding neutral
 *   color _and_ the foreground color to the appropriate contrast color (black
 *   or white) for given neutral color.
 * - `border-${neutral}` sets the border to a solid, 1px-wide border of the
 *   corresponding neutral color.
 * - `border-color-${neutral}` sets only the border color to the corresponding
 *   neutral color.
 * - `border-style-solid`, `border-style-dashed`, and `border-style-dotted` set
 *   the border style to solid, dashed, or dotted, respectively.
 * - `border-${px}` sets the border to a solid, `px`-pixel-wide border where
 *   `px` can be any integer from 1 to 8.
 * - `border-width-${px}` sets only the border width to be `px` pixels wide,
 *   where `px` can be any integer from 1 to 8.
 * - `shadow-${shadow}` sets the box shadow to the corresponding elevation
 *   level.
 * - `relative` sets position to `relative`.
 *
 * ```js
 *
 * import { cx } from '@politico/interactive-style';
 * ```
 *
 * @param {any} ...args
 *   Any arguments that you can pass to the `classnames` function. All of the
 *   resulting individual classnames will be mapped as utility classes. If
 *   they are not valid utility classes they will be included as-is by default.
 * @returns {string}
 */
const cx = merge({}, {
  strict: false
});
cx.merge = merge;
cx.strict = merge({});
export default cx;