import {
	useBlockProps,
	useInnerBlocksProps,
	useBlockEditContext,
	store as blockEditorStore,
	InspectorControls,
	ButtonBlockAppender,
} from '@wordpress/block-editor';
import { PanelBody, RangeControl, TextareaControl, TextControl, ToggleControl } from "@wordpress/components";
import { useRefEffect } from '@wordpress/compose';
import { select, subscribe } from '@wordpress/data';
import { Swiper } from 'swiper';
import { A11y, FreeMode, Pagination, Navigation } from 'swiper/modules';
import { memo, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import "./editor.scss";

const Carousel = memo(({clientId, attributes, innerBlocksProps, isSelected})=> {
  const carouselRef = useRefEffect((el) => {
    const params = {
      ...attributes
    }
    // init carousel
    const initCarousel = (container, params = {}) => {
      const parameters = {
        a11y: {
          scrollOnFocus: true,
          containerMessage: params.ariaLabel
        },
        createElements: true,
        initialSlide: 0,
        centeredSlides: false,
        slideToClickedSlide: true,
        simulateTouch: false,
        spaceBetween: params.carouselGap,
        modules: [
          Pagination, A11y, FreeMode, Navigation
        ],
        slidesPerView: params.perPageMobile,
        freemode: true,
        grabCursor: true,
        slidesPerGroup: params.perGroupMobile,
        ...(params.enableAutoPlay &&
          {autoplay: {
            delay: params.autoPlayDelay
          }}
        ),
        breakpoints: {
          768: {
            slidesPerView: params.perPageTablet,
            slidesPerGroup: params.perGroupTablet,
          },
          960: {
            slidesPerView: params.perPage,
            slidesPerGroup: params.perGroup,
          },
        },
        loop: params.enableLoop,
        pagination: {
          enabled: params.showPagination ?? false,
          clickable: true,
          hideOnClick: false
        },
        navigation: {
          enabled: params.showNavigation ?? false
        },
        // Workaround to show pagination after disabling and re-enabling
        
          on: {
            init: function() {
              if (params.showPagination) {
                container.classList.remove('swiper-pagination-disabled')
              }
              if (params.showNavigation) {
                container.classList.remove('swiper-navigation-disabled')
              }
            }
          }
      };
      return new Swiper(container, parameters);
    }
    let carousel = initCarousel(
      el,
      params
    );
    
    let slideOrder = select( blockEditorStore ).getBlockOrder( clientId );

    const unsubscribeSliderUpdateListener = subscribe(() => {
      const currSlideOrder = select( blockEditorStore ).getBlockOrder( clientId );
      // Check if slider has been changed.
      if (currSlideOrder.toString() !== slideOrder.toString()) {
        const selectedBlock = select( blockEditorStore ).getSelectedBlock();
        const slideAdded = currSlideOrder.length > slideOrder.length;
				const slideRemoved = currSlideOrder.length < slideOrder.length;
				const slideMoved = currSlideOrder.length === slideOrder.length;
				const activeIndex = carousel.activeIndex;

        // Store the current slide order before destroying the slider instance.
				slideOrder = currSlideOrder;
        carousel.destroy();

        window.requestAnimationFrame(() => {
          // init carousel
          carousel = initCarousel(el, params);

          // Determine where carousel should go
          let slideToIndex = activeIndex;
          if ( slideAdded ) {
            slideToIndex = slideOrder.length;
          } else if ( slideRemoved ) {
            slideToIndex = activeIndex - 1;
          } else if ( slideMoved ) {
            slideToIndex = slideOrder.findIndex(
              (clientId) => clientId === selectedBlock.clientId // eslint-disable-line no-shadow
            );
          }

          if ( slideToIndex < 0 ) {
						slideToIndex = 0;
					}

          carousel.slideTo(slideToIndex, 0);

        })
      }
    });
    return () => {
      unsubscribeSliderUpdateListener();
      carousel.destroy();
    }
  })

  return (
    <>
      <div className="swiper-container">
        <div className="swiper ucla-carousel" ref={carouselRef}>
          <div {...innerBlocksProps} />
        </div>
      </div>
      {isSelected &&
        <ButtonBlockAppender
          className="slider-appender has-icon"
          rootClientId={ clientId }
        />
      }
    </>
  )
})

export default function Edit({attributes, setAttributes, isSelected}) {
  let { perPage, perPageTablet, perPageMobile, perGroup, perGroupTablet, perGroupMobile, ariaLabel, showPagination, showNavigation, enableLoop, enableAutoPlay, autoPlayDelay, carouselGap } = attributes;
  const [ showBreakPoints, setShowBreakPoints ] = useState(perPageTablet || perPageMobile);
  const [ showGroupBreakPoints, setShowGroupBreakPoints ] = useState(perGroupTablet || perGroupMobile);
  const [ showAutoPlayDelay, setShowAutoPlayDelay ] = useState(enableAutoPlay)
  const { clientId } = useBlockEditContext();
  const blockProps = useBlockProps();
  const innerBlocksProps = useInnerBlocksProps(
    {className: 'swiper-wrapper'},
    {
      allowedBlocks: ["ucla-wordpress-plugin/carousel-slide"],
      template: [
        ["ucla-wordpress-plugin/carousel-slide", {}],
        ["ucla-wordpress-plugin/carousel-slide", {}],
        ["ucla-wordpress-plugin/carousel-slide", {}],
      ],
      orientation: 'horizontal',
      renderAppender: false,
    }
  )
  const onResponsiveChange = value => {
    setShowBreakPoints(!showBreakPoints);
    if (value) {
      setAttributes({perPageMobile: null, perPageTablet: null});
    }
  }
  const onResponsiveGroupChange = value => {
    setShowGroupBreakPoints(!showGroupBreakPoints);
    if (value) {
      setAttributes({perGroupMobile: null, perGroupTablet: null});
    }
  }
  const onEnableAutoPlay = value => {
    setShowAutoPlayDelay(!enableAutoPlay);
  }
  return (
    <>
      <InspectorControls>
      <PanelBody title="Settings">
          <RangeControl
            label="Number of Items per view"
            max={4}
            min={1}
            step={1}
            value={perPage}
            onChange={(value) => {
              setAttributes({ perPage: value });
            }}
          />
          {showBreakPoints &&
          <>
            <RangeControl
              label="Number of Items per view on tablet"
              max={4}
              min={1}
              step={1}
              value={perPageTablet}
              onChange={(value) => {
                setAttributes({ perPageTablet: value });
              }}
            />
            <RangeControl
              label="Number of Items per view on mobile"
              max={4}
              min={1}
              step={1}
              value={perPageMobile}
              onChange={(value) => {
                setAttributes({ perPageMobile: value });
              }}
            />
          </>
          }
          <ToggleControl
            checked={showBreakPoints}
            onChange={()=>onResponsiveChange(showBreakPoints)}
            label="Responsive Slides"
            help="Change the number of slides per view on tablet or mobile"
          />
          <hr />
          <RangeControl
            label="Numbers of grouped items to slide"
            max={4}
            min={1}
            step={1}
            value={perGroup}
            onChange={(value) => {
              setAttributes({ perGroup: value });
            }}
          />
          {showGroupBreakPoints &&
          <>
            <RangeControl
              label="Numbers of grouped items to slide on tablet"
              max={4}
              min={1}
              step={1}
              value={perGroupTablet}
              onChange={(value) => {
                setAttributes({ perGroupTablet: value });
              }}
            />
            <RangeControl
              label="Numbers of grouped items to slide on mobile"
              max={4}
              min={1}
              step={1}
              value={perGroupMobile}
              onChange={(value) => {
                setAttributes({ perGroupMobile: value });
              }}
            />
          </>
          }
          <ToggleControl
            checked={showGroupBreakPoints}
            onChange={()=>onResponsiveGroupChange(showGroupBreakPoints)}
            label="Responsive Group"
            help="Change the number of grouped items on tablet or mobile"
          />
          <hr />
          <RangeControl
              label="Carousel Gap"
              max={24}
              min={0}
              step={4}
              value={carouselGap}
              onChange={(value) => {
                setAttributes({ carouselGap: value });
              }}
            />
          <hr />
          <ToggleControl
            checked={showPagination}
            onChange={(value)=>{
              setAttributes({showPagination:value});
            }}
            label="Show Pagination"
            help="Shows the bullet indicators below the carousel"
          />
          <hr />
          <ToggleControl
            checked={showNavigation}
            onChange={(value)=>{
              setAttributes({showNavigation:value});
            }}
            label="Show navigation"
            help="Shows the arrow indicators for the carousel"
          />
          <hr />
          <ToggleControl
            checked={enableLoop}
            onChange={(value)=>{
              setAttributes({enableLoop:value});
            }}
            label="Enable Loop"
            help="Loops back to first slide"
          />
          <hr />
          <ToggleControl
            checked={enableAutoPlay}
            onChange={(value)=>{
              setAttributes({enableAutoPlay:value});
            }}
            label="Enable Autoplay"
            help="Set carousel to automatically slide"
          />
          {enableAutoPlay &&
            <TextControl
              label="Delay per slide in milliseconds"
              value={autoPlayDelay}
              type="number"
              onChange={(value)=>setAttributes({autoPlayDelay:value})}
            />
          }
          <hr />
          <TextareaControl
            label="Aria Label"
            help="Describe the purpose of this carousel"
            value={ariaLabel}
            onChange={(value)=>setAttributes({ariaLabel: value})}
          />
        </PanelBody>
      </InspectorControls>
      <div {...blockProps}>
        <Carousel
          clientId={clientId}
          attributes={attributes}
          innerBlocksProps={innerBlocksProps}
          isSelected={isSelected}
        />
      </div>
    </>
  )
}