/**
 * WordPress dependencies
 */
import { useEffect } from "@wordpress/element";
import { addFilter } from "@wordpress/hooks";
import { useDispatch, useSelect } from "@wordpress/data";
import { usePrevious } from "@wordpress/compose";
import { store as blockEditorStore } from "@wordpress/block-editor";

/**
 * Internal dependencies
 */
import { useValueRef, useIsMounted, getBreakpointType } from "sdk/utils";
import { hasSupportLayout } from "../../utils";
import { triggerEvent } from "../../utils/dom";
import { getCarouselManager, addCarousel } from "./carousel-script";
import { featureName, layoutType } from "./carousel";

/**
 * Trigger carousel preview event
 *
 * @param {Object}
 * @returns
 */
export const triggerCarouselPreview = ({
  props,
  blockElement,
  previewMode,
  getSelectedBlockClientId,
  selectBlock,
  ...otherProps
}) => {
  const args = {
    ...props,
    ...otherProps,
    blockElement,
    previewMode,
    clickHandler: (e) => {
      e.preventDefault();
      const selectedId = getSelectedBlockClientId();
      const blockId = props?.postTemplateId ?? props?.clientId;
      if (selectedId !== blockId) {
        selectBlock(blockId);
      }
    },
  };

  triggerEvent(window, "cbb.carousel.updated", args);

  return () => {
    triggerEvent(window, "cbb.carousel.disposed", args);
  };
};

/**
 * Handle carousel script
 */
addFilter(
  "boldblocks.edit.blockEditInner",
  `cbb/carousel/editor`,
  (content, props) => {
    if (hasSupportLayout(props.name, featureName, layoutType)) {
      const { ref, attributes } = props;

      const { getSelectedBlockClientId } = useSelect(
        (select) => select(blockEditorStore),
        [],
      );
      const { selectBlock } = useDispatch(blockEditorStore);

      // Get current breakpoint
      const breakpoint = getBreakpointType();

      let previewMode = attributes.boldblocks.carousel.previewMode;

      if (breakpoint !== "lg") {
        previewMode = "EDIT";
      }

      const isMounted = useIsMounted();
      const lastPreviewMode = usePrevious(previewMode);
      const valueRef = useValueRef(attributes.boldblocks.carousel);
      useEffect(() => {
        if (previewMode === "PREVIEW" || lastPreviewMode === "PREVIEW") {
          return triggerCarouselPreview({
            props,
            blockElement: ref.current,
            previewMode,
            getSelectedBlockClientId,
            selectBlock,
            isMounted,
          });
        }
      }, [previewMode, valueRef.current]);
    }

    return content;
  },
);

/**
 * Kick start
 */
window.addEventListener("cbb.carousel.updated", ({ detail }) => {
  if (detail?.isMounted) {
    setTimeout(() => {
      buildPreviewCarousel(detail);
    }, 1);
  } else {
    buildPreviewCarousel(detail);
  }
});

/**
 * Dispose
 */
window.addEventListener("cbb.carousel.disposed", ({ detail: { clientId } }) => {
  removeCarouselPreview(`block-${clientId}`);
});

export const removeCarouselPreview = (instanceId) => {
  const manager = getCarouselManager();
  if (manager[instanceId]) {
    const slider = manager[instanceId];
    slider.dispose();
    if (slider.sliderElement) {
      slider.sliderElement.remove();
    }
    delete manager[instanceId];
  }
};

function buildPreviewCarousel({
  blockElement,
  name: blockName,
  clientId,
  previewMode,
  clickHandler,
}) {
  const instanceId = `block-${clientId}`;
  removeCarouselPreview(instanceId);
  if (previewMode === "PREVIEW") {
    let carouselElement = blockElement.cloneNode(true);
    carouselElement.addEventListener("click", clickHandler);
    const appender = carouselElement.querySelector(".block-list-appender");
    if (appender) {
      appender.remove();
    }
    const editBlocks = carouselElement.querySelectorAll("[contenteditable]");
    editBlocks.forEach((block) => block.removeAttribute("contenteditable"));
    blockElement.insertAdjacentElement("afterend", carouselElement);

    const args = {
      instanceId,
      isClone: true,
    };

    if (blockName === "core/post-template") {
      args["datasetSelector"] = "ul";

      const activePost = carouselElement.querySelector("li[data-is-drop-zone]");
      if (activePost) {
        const hiddenPost = activePost.nextElementSibling;
        if (
          hiddenPost &&
          window.getComputedStyle(hiddenPost).display === "none"
        ) {
          hiddenPost.remove();
        }
      }
    }

    addCarousel(carouselElement, args);
  }
}
