// External dependencies.
import React, { ReactElement } from 'react';

// Divi dependencies.
import {
  StyleContainer,
  StylesProps,
} from '@divi/module';

// Local dependencies.
import { ListingGridAttrs } from './types';
import {
  createTypographyStyles,
  extractTypographyAttrs,
} from '../../utils';

const mapResponsiveValue = (attr: any, map: (value: string) => string) => {
  if (!attr) {
    return null;
  }

  const breakpoints = ['desktop', 'tablet', 'phone'];
  const hasBreakpointValue = breakpoints.some((breakpoint) => undefined !== attr?.[breakpoint]);

  if (hasBreakpointValue) {
    const next = { ...attr };

    breakpoints.forEach((breakpoint) => {
      if (undefined === attr?.[breakpoint]) {
        return;
      }

      const value = attr?.[breakpoint]?.value ?? attr?.[breakpoint]?.default;

      if (undefined === value || null === value || '' === value) {
        return;
      }

      const mapped = map(String(value));
      next[breakpoint] = {
        ...attr[breakpoint],
        value: mapped,
        default: mapped,
      };
    });

    return next;
  }

  const value = attr?.value ?? attr?.default;

  if (undefined === value || null === value || '' === value) {
    return attr;
  }

  const mapped = map(String(value));

  return {
    ...attr,
    value: mapped,
    default: mapped,
  };
};

/**
 * Dynamic Module style components.
 */
const ModuleStyles = ({
  settings,
  mode,
  state,
  noStyleTag,
  elements,
  attrs,
  orderClass,
}: StylesProps<ListingGridAttrs>): ReactElement => {
  const selectors = {
    grid: `${orderClass} .jet-listing-grid`,
    items:
      `${orderClass} :is(` +
      `.jet-listing-grid > .jet-listing-grid__items, ` +
      `.jet-listing-grid > [data-slider_options] > .jet-listing-grid__items > .slick-list > .slick-track, ` +
      `.jet-listing-grid > .jet-listing-grid__scroll-slider > .jet-listing-grid__items` +
      `) > .jet-listing-grid__item`,
    itemsWrap:
      `${orderClass} :is(` +
      `.jet-listing-grid, ` +
      `.jet-listing-grid > [data-slider_options], ` +
      `.jet-listing-grid > .jet-listing-grid__scroll-slider` +
      `) > .jet-listing-grid__items`,
    collapseGap: `${orderClass} .jet-listing-grid__items.grid-collapse-gap`,
    loader: `${orderClass} .jet-listing-grid__loader`,
    loaderText: `${orderClass} .jet-listing-grid__loader-text`,
    sliderIcon: `${orderClass} .jet-listing-grid__slider-icon`,
    sliderIconHover: `${orderClass} .jet-listing-grid__slider-icon:hover`,
    sliderIconSvgPath: `${orderClass} .jet-listing-grid__slider-icon svg path`,
    sliderIconSvgPathHover: `${orderClass} .jet-listing-grid__slider-icon:hover svg path`,
    dots: `${orderClass} .jet-listing-grid__slider .jet-slick-dots li`,
    dotsHover: `${orderClass} .jet-listing-grid__slider .jet-slick-dots li:hover`,
    dotsActive: `${orderClass} .jet-listing-grid__slider .jet-slick-dots li.slick-active`,
    notFound: `${orderClass} .jet-listing-not-found`,
  };

  const loaderTextTypography = extractTypographyAttrs(attrs?.module?.decoration?.loaderTextTypography);
  const loaderTextTypographyStyles = createTypographyStyles(selectors.loaderText, loaderTextTypography);

  const notFoundTypography = extractTypographyAttrs(attrs?.module?.decoration?.notFoundTypography);
  const notFoundTypographyStyles = createTypographyStyles(selectors.notFound, notFoundTypography);
  const horizontalGapHalf = mapResponsiveValue(attrs?.module?.decoration?.horizontalGap, (value) => `calc(${value} / 2)`);
  const horizontalGapNegativeHalf = mapResponsiveValue(attrs?.module?.decoration?.horizontalGap, (value) => `calc(-${value} / 2)`);
  const horizontalGapWidth = mapResponsiveValue(attrs?.module?.decoration?.horizontalGap, (value) => `calc(100% + ${value})`);
  const verticalGapHalf = mapResponsiveValue(attrs?.module?.decoration?.verticalGap, (value) => `calc(${value} / 2)`);
  const verticalGapNegativeHalf = mapResponsiveValue(attrs?.module?.decoration?.verticalGap, (value) => `calc(-${value} / 2)`);
  const arrowsZIndex = mapResponsiveValue(
    attrs?.module?.decoration?.arrowsZIndex,
    (value) => value.replace(/[^0-9.-]/g, ''),
  );

  return (
    <StyleContainer mode={mode} state={state} noStyleTag={noStyleTag}>
      {elements.style({
        attrName: 'module',
        styleProps: {
          disabledOn: {
            disabledModuleVisibility: settings?.disabledModuleVisibility,
          },
          advancedStyles: [
            ...loaderTextTypographyStyles,
            ...notFoundTypographyStyles,
            {
              componentName: 'divi/common',
              props: {
                property: '--jet-listing-grid-h-gap',
                selector: selectors.grid,
                attr: attrs?.module?.decoration?.horizontalGap,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'padding-left',
                selector: selectors.items,
                attr: horizontalGapHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'padding-right',
                selector: selectors.items,
                attr: horizontalGapHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'margin-left',
                selector: selectors.itemsWrap,
                attr: horizontalGapNegativeHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'margin-right',
                selector: selectors.itemsWrap,
                attr: horizontalGapNegativeHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'width',
                selector: selectors.itemsWrap,
                attr: horizontalGapWidth,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--jet-listing-grid-v-gap',
                selector: selectors.grid,
                attr: attrs?.module?.decoration?.verticalGap,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'padding-top',
                selector: selectors.items,
                attr: verticalGapHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'padding-bottom',
                selector: selectors.items,
                attr: verticalGapHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'margin-top',
                selector: selectors.collapseGap,
                attr: verticalGapNegativeHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'margin-bottom',
                selector: selectors.collapseGap,
                attr: verticalGapNegativeHalf,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--jet-listing-grid-center-padding',
                selector: selectors.grid,
                attr: attrs?.module?.decoration?.centerModePadding,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--jet-listing-grid-arrow-box-size',
                selector: selectors.grid,
                attr: attrs?.module?.decoration?.arrowsBoxSize,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--jet-listing-grid-arrow-size',
                selector: selectors.grid,
                attr: attrs?.module?.decoration?.arrowsSize,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--jet-listing-grid-dots-size',
                selector: selectors.grid,
                attr: attrs?.module?.decoration?.dotsSize,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--jet-listing-grid-dots-gap',
                selector: selectors.grid,
                attr: attrs?.module?.decoration?.dotsGap,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--spinner-color',
                selector: selectors.loader,
                attr: attrs?.module?.decoration?.loaderColor,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: '--spinner-size',
                selector: selectors.loader,
                attr: attrs?.module?.decoration?.loaderSize,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'color',
                selector: selectors.loaderText,
                attr: attrs?.module?.decoration?.loaderTextColor,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'z-index',
                selector: selectors.sliderIcon,
                attr: arrowsZIndex,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'color',
                selector: selectors.sliderIcon,
                attr: attrs?.module?.decoration?.arrowColor,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'fill',
                selector: selectors.sliderIconSvgPath,
                attr: attrs?.module?.decoration?.arrowColor,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'background',
                selector: selectors.sliderIcon,
                attr: attrs?.module?.decoration?.arrowBgColor,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'color',
                selector: selectors.sliderIconHover,
                attr: attrs?.module?.decoration?.arrowColorHover,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'fill',
                selector: selectors.sliderIconSvgPathHover,
                attr: attrs?.module?.decoration?.arrowColorHover,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'background',
                selector: selectors.sliderIconHover,
                attr: attrs?.module?.decoration?.arrowBgColorHover,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'background',
                selector: selectors.dots,
                attr: attrs?.module?.decoration?.dotsBgColor,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'background',
                selector: selectors.dotsHover,
                attr: attrs?.module?.decoration?.dotsBgColorHover,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'background',
                selector: selectors.dotsActive,
                attr: attrs?.module?.decoration?.dotsBgColorActive,
              },
            },
            {
              componentName: 'divi/common',
              props: {
                property: 'color',
                selector: selectors.notFound,
                attr: attrs?.module?.decoration?.notFoundColor,
              },
            },
          ],
        },
      })}
    </StyleContainer>
  );
};

export {
  ModuleStyles,
};
