import React from 'react';
import { Portal } from 'react-portal';
import { connect } from 'react-redux';
import cx from 'classnames';
import BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
import { getFieldURL } from '@plone/volto/helpers/Url/Url';
import Image from '@plone/volto/components/theme/Image/Image';
import config from '@plone/volto/registry';
import { withCachedImages } from '@eeacms/volto-block-style/hocs';
import './stretchStyleDefaultView.css';
import './stretchStyleWideView.css';
import './stretchStyleEdit.css';

const getLineHeight = (fontSize) => {
  switch (fontSize) {
    case 'large':
      return '110%';
    case 'x-large':
      return '130%';
    default:
      return;
  }
};

const getSide = (side, v) => {
  const v_unit = v.unit ? v.unit : 'px';
  return `${v[side] ? `${v[side]}${v_unit}` : '0px'}`;
};

const getSides = (v) => {
  return `${getSide('top', v)} ${getSide('right', v)} ${getSide(
    'bottom',
    v,
  )} ${getSide('left', v)}`;
};

const hexColorToRGB = (hex) => {
  const R = parseInt(hex.slice(1, 3), 16);
  const G = parseInt(hex.slice(3, 5), 16);
  const B = parseInt(hex.slice(5, 7), 16);
  return [R, G, B];
};

const h2rgb = (hex) => {
  if (!hex) return '0, 0, 0, ';
  const [R, G, B] = hexColorToRGB(hex);
  return `${R}, ${G}, ${B},`;
};

function IsomorphicPortal({ children }) {
  const [isClient, setIsClient] = React.useState();
  React.useEffect(() => setIsClient(true), []);

  return isClient ? (
    <Portal node={document.getElementById('page-header')}>{children}</Portal>
  ) : (
    children
  );
}

export function getInlineStyles(data, props = {}) {
  return {
    ...(data.hidden && props.mode !== 'edit' ? { display: 'none' } : {}),
    ...(data.backgroundColor
      ? {
          backgroundColor: data.backgroundColor,
          '--background-color': data.backgroundColor,
        }
      : {}),
    ...(data.textColor
      ? { color: data.textColor, '--text-color': data.textColor }
      : {}),
    ...(data.textAlign ? { textAlign: data.textAlign } : {}),
    ...(data.fontSize
      ? { fontSize: data.fontSize, lineHeight: getLineHeight(data.fontSize) }
      : {}),
    ...(data.fontWeight ? { fontWeight: data.fontWeight } : {}),
    ...(data.height ? { height: data.height } : {}),
    ...(data.isScreenHeight && props.screen.height
      ? {
          minHeight: (
            props.screen.height -
            props.screen.browserToolbarHeight -
            props.screen.content.offsetTop
          ).toPixel(),
        }
      : {}),
    ...(data.shadowDepth && {
      boxShadow: `0px 0px ${data.shadowDepth}px rgba(${h2rgb(
        data.shadowColor,
      )} ${(data.shadowDepth * 100) / 0.24})`,
    }),
    ...(data.margin && { margin: getSides(data.margin) }),
    ...(data.padding && { padding: getSides(data.padding) }),
    ...(data.borderRadius && {
      borderRadius: data.borderRadius,
    }),
    ...(data.clear && {
      clear: data.clear,
    }),
    // fill in more
  };
}

export function getStyle(name) {
  const { pluggableStyles = [] } = config.settings;
  return pluggableStyles.find(({ id }) => id === name);
}

const StyleWrapperView = (props) => {
  const { styleData = {}, data = {}, mode = 'view' } = props;
  const {
    style_name,
    align,
    size,
    customClass,
    theme,
    customId,
    isDropCap,
    isScreenHeight,
    useAsPageHeader = false,
    hidden = false,
    stretch,
  } = styleData;

  const containerType = data['@type'];
  const backgroundImage = getFieldURL(styleData.backgroundImage);

  const style = getStyle(style_name);
  const inlineStyles = getInlineStyles(styleData, props);
  const styled =
    props.styled ||
    Object.keys(inlineStyles).length > 0 ||
    backgroundImage ||
    style ||
    align ||
    size ||
    customClass ||
    theme ||
    isDropCap ||
    hidden ||
    customId ||
    stretch;

  const attrs = {
    style: inlineStyles,
    className: cx(
      `styled-${containerType}`,
      style?.cssClass,
      customClass,
      theme,
      align,
      props.className,
      {
        align,
        styled,
        'styled-with-bg': styleData.backgroundColor || backgroundImage,
        'screen-height': isScreenHeight,
        'full-width': align === 'full',
        stretch: stretch === 'stretch',
        large: size === 'l',
        medium: size === 'm',
        small: size === 's',
        'drop-cap': isDropCap,
        [`has--fontSize--${inlineStyles['fontSize']}`]:
          !!inlineStyles['fontSize'] && mode === 'edit',
      },
    ),
    id: customId,
    ...(props.role ? { role: props.role } : {}),
  };

  const nativeIntegration =
    mode === 'view' &&
    config.settings.integratesBlockStyles.includes(containerType);

  const children = nativeIntegration
    ? Object.keys(styleData).length > 0
      ? React.Children.map(props.children, (child) => {
          const childProps = { ...props, styling: attrs };
          if (React.isValidElement(child)) {
            return React.cloneElement(child, childProps);
          }
          return child;
        })
      : props.children
    : props.children;

  const ViewComponentWrapper = style?.viewComponent;
  const StyleWrapperRendered = styled ? (
    nativeIntegration && !style_name?.includes('content-box') ? (
      children
    ) : (
      <div {...attrs} ref={props.setRef}>
        {Object.keys(props.images || {}).map((bgImage) => (
          <Image
            key={`styled-bg-image-${bgImage}`}
            alt=""
            src={props.images[bgImage]?.src}
            className={cx('bg', {
              hidden:
                backgroundImage !== bgImage || !props.images[bgImage]?.src,
            })}
          />
        ))}

        {ViewComponentWrapper ? <ViewComponentWrapper {...props} /> : children}
      </div>
    )
  ) : ViewComponentWrapper ? (
    <ViewComponentWrapper {...props} />
  ) : (
    children
  );

  return useAsPageHeader ? (
    <React.Fragment>
      <BodyClass className="custom-page-header" />
      <IsomorphicPortal>{StyleWrapperRendered}</IsomorphicPortal>
    </React.Fragment>
  ) : (
    StyleWrapperRendered
  );
};

export default connect((state, ownProps) =>
  ownProps.styleData.isScreenHeight ? { screen: state.screen } : {},
)(
  withCachedImages(StyleWrapperView, {
    getImage: (props) => props.styleData.backgroundImage || null,
  }),
);
