import { Children, cloneElement } from 'react';
import classNames from 'classnames';
import css from 'styled-jsx/css';

import type { ReactElement } from 'react';

const HOVER_STYLE = `opacity: 1 !important; transition-duration: .3s !important;`;

const styles = css.resolve`
  :hover .bg,
  :focus-visible .bg {
    ${HOVER_STYLE}
  }
`;

/**
 * Injects a subtle semi-opaque background that
 * fades in/out on hover or focus.
 */
const HoverBackground = ({
  color = 'rgba(255,255,255,0.05)',
  children,
  selectorFromFocusableEl,
}: {
  className?: string;
  children: ReactElement;
  color?: string;

  /**
   * When the focusable element isn't an ancestor of `div.bg` you can
   * provide a css selector path from the focusable element to `div.bg`.
   */
  selectorFromFocusableEl?: string;
}) => {
  const child = Children.only<any>(children);

  // mutate the first child injecting the required styling, classes and child nodes
  return cloneElement(child, {
    ...child.props,
    className: classNames(child.props.className, styles.className, 'hoverBg'),

    style: {
      ...child.props.style,
      position: 'relative',
      // clip background when container has corners
      overflow: 'hidden',
    },

    children: (
      <>
        {child.props.children}
        <div
          className={`${styles.className} bg`}
          style={{
            position: 'absolute',
            left: 0,
            top: 0,
            bottom: 0,
            right: 0,
            zIndex: 0,
            opacity: 0,
            transition: 'opacity .6s',
            background: color,
            pointerEvents: 'none',
          }}
        />
        {styles.styles}
        {/* some complex cases need to provide custom selector from focusable el to bg */}
        {selectorFromFocusableEl && (
          <style jsx>{`
            .hoverBg :focus-visible ${selectorFromFocusableEl} .bg {
              ${HOVER_STYLE}
            }
          `}</style>
        )}
      </>
    ),
  });
};

export default HoverBackground;
