import { forwardRef } from 'react';
import PropTypes from 'prop-types';
import useResponsiveValues from "../../../hooks/breakpoint/useResponsiveValues/index.js";
import CustomPropTypes from "../../../utils/prop-types/index.js";
import getColor from "../../../utils/colors/getColor.js";
import cx from "../../../utils/css/cx.js";
import getPaddingClasses from "../../../utils/css/getPaddingClasses.js";
import getMarginClasses from "../../../utils/css/getMarginClasses.js";
import getBorderClasses from "../../../utils/css/getBorderClasses.js";
import getEdgeClasses from "../../../utils/css/getEdgeClasses.js";
import getShadowClasses from "../../../utils/css/getShadowClasses.js";
import normalizeAlign from './utils/normalizeAlign';
import classes from './styles.module.scss';

/**
 * Renders a container that positions elements in the same way as Figma's auto
 * layout.
 *
 * ```js
 *
 * import { AutoLayout } from '@politico/interactive-style';
 * ```
 */
const AutoLayout = forwardRef((props, ref) => {
  const {
    as: Tag,
    direction: directionProp,
    align,
    gap,
    padding,
    margin,
    shadow,
    border,
    edge,
    bg,
    fg,
    relative,
    children,
    wrap
  } = props;

  // direction
  const direction = useResponsiveValues(directionProp);

  // padding
  const paddingValue = useResponsiveValues(padding);
  const pads = getPaddingClasses(paddingValue);

  // margins
  const marginValue = useResponsiveValues(margin);
  const margins = getMarginClasses(marginValue);

  // alignment
  const alignValue = useResponsiveValues(align);
  const alignment = normalizeAlign({
    align: alignValue,
    gap,
    direction
  });

  // borders
  const [borderClasses, borderValues] = getBorderClasses(border, {
    classAttributes: ['style', 'width']
  });

  // gap
  const gapValue = useResponsiveValues(gap);
  const edgeClasses = getEdgeClasses(edge);
  const shadowClasses = getShadowClasses(shadow);
  return <Tag ref={ref} className={cx.merge(classes)('container', `direction-${direction}`, `align-${alignment}`, `gap-${gapValue}`, edgeClasses, shadowClasses, pads, margins, borderClasses, {
    relative,
    wrapForward: wrap === true || wrap === 'forward',
    wrapReverse: wrap === 'reverse',
    wrapNone: wrap === false || wrap === 'none'
  })} style={{
    '--AutoLayout-bg': getColor(bg),
    '--AutoLayout-fg': getColor(fg),
    '--AutoLayout-border-color': getColor(borderValues.color)
  }}>
      {children}
    </Tag>;
});
AutoLayout.displayName = 'AutoLayout';
AutoLayout.defaultProps = {
  as: 'div',
  direction: 'vertical',
  align: 'topLeft',
  gap: '4',
  padding: undefined,
  margin: undefined,
  shadow: undefined,
  border: undefined,
  edge: undefined,
  bg: undefined,
  fg: undefined,
  relative: false,
  children: undefined,
  wrap: undefined
};
AutoLayout.propTypes = {
  /**
   * Control which kind of tag or component is used to render the auto layout
   * container. If you use a custom component it will be passed `className` and
   * `ref` props.
   */
  as: PropTypes.elementType,
  /**
   * The direction of the auto layout, either vertical (↓) or horizontal (→).
   */
  direction: CustomPropTypes.responsive(PropTypes.oneOfType([PropTypes.oneOf(['vertical', 'horizontal'])])),
  /**
   * The alignment of elements within the auto layout. This can either be
   * a Figma-style alignment value or a native value for the CSS property
   * `align-items`.
   */
  align: CustomPropTypes.responsive(PropTypes.oneOfType([PropTypes.oneOf(['topLeft', 'topCenter', 'topRight', 'left', 'center', 'right', 'bottomLeft', 'bottomCenter', 'bottomRight', 'baseline']), PropTypes.string])),
  /**
   * The spacing level that should be used as a gap between elements in the
   * auto layout. This can either be a spacing value (e.g., `"4"` to mean
   * `$spacing-4`) or `"space-between"` to distribute the space between items
   * evenly.
   */
  gap: CustomPropTypes.responsive(PropTypes.string),
  /**
   * The padding of the auto layout. Padding can be specified as one spacing
   * value that gets used on all sides, separate `x` and `y` values, or
   * completely separate `trbl` values. The values correspond to levels of our
   * spacing scale (e.g., `"4"` corresponds to `$spacing-4`).
   */
  padding: CustomPropTypes.responsive(PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    x: PropTypes.string,
    y: PropTypes.string
  }), PropTypes.shape({
    t: PropTypes.string,
    r: PropTypes.string,
    b: PropTypes.string,
    l: PropTypes.string
  })])),
  /**
   * The margin around the auto layout. Margins can be specified as one spacing
   * value that gets used on all sides, separate `x` and `y` values, or
   * completely separate `trbl` values. The values correspond to levels of our
   * spacing scale (e.g., `"4"` corresponds to `$spacing-4`).
   */
  margin: CustomPropTypes.responsive(PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    x: PropTypes.string,
    y: PropTypes.string
  }), PropTypes.shape({
    t: PropTypes.string,
    r: PropTypes.string,
    b: PropTypes.string,
    l: PropTypes.string
  })])),
  /**
   * Sets the elevation level of the auto layout. See the section on elevation
   * for guidance on which level to choose.
   */
  shadow: PropTypes.oneOf(['000', '100', '200', '300', '400']),
  /**
   * Sets the color and width of the auto layout's border. You can activate the
   * default border by setting this to `true`, you can customize just the color
   * by passing either a color name or a CSS color value as a string, or you
   * can customize both the color and the width by passing an object with they
   * keys `color` and `width`. When customizing the width, set it as
   * a numerical pixel value.
   */
  border: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.shape({
    color: PropTypes.string,
    width: PropTypes.number,
    style: PropTypes.string
  })]),
  /**
   * Sets the roundedness of the auto layout's corners. These correspond to
   * levels of our spacing scale (e.g., `"2"` corresponds to `$spacing-2`). You
   * can also use the aliases `sharp` and `round`, which correspond to `"0"`
   * and `"2"`, respectively.
   */
  edge: PropTypes.oneOf(['0', '1', '2', '4', '5', '6', '8', 'sharp', 'round', 'max']),
  /**
   * Sets the background color of the auto layout, which is unset by default.
   * This prop accepts either a color name provided by this library or a CSS
   * color value.
   */
  bg: PropTypes.string,
  /**
   * Sets the foreground color of the card, which will be inherited by default.
   * This prop accepts either a color name provided by this library or a CSS
   * color value.
   */
  fg: PropTypes.string,
  /**
   * Whether the auto layout should specify `position: relative` to allow
   * absolute positioning within it.
   */
  relative: PropTypes.bool,
  /**
   * How flexbox should handle wrapping.
   */
  wrap: PropTypes.oneOf([true, false, 'forwards', 'reverse', 'none']),
  /**
   * The children that should be rendered within the auto layout.
   */
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)])
};
export default AutoLayout;