import React from 'react';
import createEmotion from '@emotion/css/create-instance';
import isPropValid from '@emotion/is-prop-valid';

export const {
  flush,
  hydrate,
  cx,
  merge,
  getRegisteredStyles,
  injectGlobal,
  keyframes,
  css,
  sheet,
  cache,
} = createEmotion({ key: 'css' });

const shouldForwardProp = (prop) => isPropValid(prop);

const getFilteredProps = (props) => {
  const filteredProps = {};

  for (const key in props) {
    if (shouldForwardProp(key)) {
      filteredProps[key] = props[key];
    }
  }

  return filteredProps;
};

export const styled = (Component) => (styles) => {
  // Compiling initial styledm component styles
  const compiledStyles = css(styles);

  const StyledComponent = React.forwardRef((props, ref) => {
    const { as, className, css: __css, ...rest } = props;
    const isBaseHTMLElement =
      typeof Component === 'string' || typeof as === 'string';

    // Rendering as
    const BaseComponent = as ? as : Component;
    // Compiling custom css prop styles
    const customStyles = __css ? css(__css) : '';
    // Compiling all classNames
    const classes = cx(compiledStyles, className, customStyles);
    // Filter non HTML props for base elements (e.g. `div`).
    const finalProps = isBaseHTMLElement ? getFilteredProps(rest) : rest;

    return <BaseComponent {...finalProps} className={classes} />;
  });

  // Setting the display name
  let displayName = 'Component';
  if (typeof Component === 'string') {
    displayName = Component;
  }
  if (Component.displayName) {
    displayName = Component.displayName;
  }
  StyledComponent.displayName = `Styled(${displayName})`;

  return StyledComponent;
};