import React, { ReactElement, useEffect, useRef } from 'react';
import { ModuleContainer, StyleContainer } from '@divi/module';
import { useFetch } from '@divi/rest';

function unwrapDiviFieldValue(value: any): any {
  if (value === null || typeof value === 'undefined') {
    return undefined;
  }

  if (typeof value !== 'object') {
    return value;
  }

  const source = Array.isArray(value) ? value : value;
  for (const key of ['value', 'desktop', 'hex', 'color', 'rgb', 'raw', 'size', 'amount']) {
    if (typeof (source as any)[key] !== 'undefined') {
      return unwrapDiviFieldValue((source as any)[key]);
    }
  }

  const entries = Object.values(source);
  if (entries.length === 1) {
    return unwrapDiviFieldValue(entries[0]);
  }

  return undefined;
}

function getFieldString(value: any, fallback: string): string {
  const normalized = unwrapDiviFieldValue(value);

  if (typeof normalized === 'undefined' || normalized === null || normalized === '') {
    return fallback;
  }

  if (typeof normalized === 'boolean') {
    return normalized ? 'on' : 'off';
  }

  return String(normalized).trim();
}

function getFieldNumber(value: any, fallback: string): string {
  const normalized = getFieldString(value, fallback);
  const match = normalized.match(/-?\d+(?:\.\d+)?/);

  return match ? match[0] : fallback;
}

function getColorField(value: any, fallback: string): string {
  const normalized = getFieldString(value, fallback);

  if (/^[0-9a-fA-F]{3,4}([0-9a-fA-F]{3,4})?$/.test(normalized)) {
    return `#${normalized}`;
  }

  return normalized;
}

function parseGalleryHash(hash: string) {
  const cleaned = (hash || '').replace(/^#/, '');
  if (!cleaned || cleaned.indexOf('-wpmfgallery+') === -1) {
    return null;
  }

  const parts = cleaned.split('-wpmfgallery+');
  if (parts.length !== 2) {
    return null;
  }

  return {
    galleryId: parts[0],
    topGalleryId: parts[1],
  };
}

// ─── Gallery theme initializers ────────────────────────────────────────────────
// These mirror the exact logic from the Divi 4 builder-bundle.min.js for Gallery Addon.
// Key difference from site_gallery.js: we call imagesLoaded as a jQuery PLUGIN METHOD
// (i.e. $(container).imagesLoaded(...)), NOT as a global function, which avoids crashes
// in Divi 5's iframe where the global may not be attached to window.

function calculateGrid($: any, $container: any) {
  // gallery addon uses data-gutter-width (hyphen), not data-gutterWidth
  const columns = parseInt($container.data('wpmfcolumns')) || 3;
  let gutterWidth = $container.data('gutter-width');
  const containerWidth = $container.width();
  if (isNaN(gutterWidth) || gutterWidth > 500 || gutterWidth < 0) gutterWidth = 5;
  gutterWidth = parseInt(gutterWidth);
  const allGutters = gutterWidth * (columns - 1);
  const columnWidth = Math.floor((containerWidth - allGutters) / columns);
  return { columnWidth, gutterWidth, columns };
}

function initMasonry($: any, wrap: HTMLElement) {
  // Structure: wrap > .wpmf_gallery_wrap > .wpmf_gallery_box > .wpmf-gallerys-addon > .gallery-masonry
  const $gallerys = $(wrap).find('.wpmf-gallerys-addon');
  if (!$gallerys.length) return;
  const $container = $gallerys.find('.gallery-masonry');
  if (!$container.length || $container.hasClass('gallery-masonry-horizontal')) return;
  $(wrap).find('.loading_gallery').hide();

  const o = calculateGrid($, $container);
  const $items = $container.children('.wpmf-gallery-item');
  $items.css({ width: o.columnWidth + 'px', 'margin-bottom': o.gutterWidth + 'px' });

  if (typeof $.fn.masonry !== 'undefined') {
    $container.masonry({
      itemSelector: '.wpmf-gallery-item',
      columnWidth: o.columnWidth,
      gutter: o.gutterWidth,
      isAnimated: true,
      isFitWidth: true,
    });
    $items.addClass('wpmf-gallery-item-show');
  }
}

function initSlider($: any, wrap: HTMLElement, numberLines: string) {
  const $slider = $(wrap).find('.wpmfslick');
  if ($slider.is(':hidden')) return;
  const columns = parseInt($slider.data('wpmfcolumns')) || 1;
  const autoPlay = $slider.data('auto_animation');
  const numLines = parseInt(numberLines) || 1;
  if ($slider.hasClass('slick-initialized')) $slider.slick('destroy');
  $slider.imagesLoaded(function() {
    $slider.slick({
      infinite: true,
      slidesToShow: parseInt(columns as any),
      slidesToScroll: parseInt(columns as any),
      pauseOnHover: true,
      autoplay: autoPlay === 1,
      adaptiveHeight: columns === 1,
      autoplaySpeed: 5000,
      rows: numLines,
      responsive: [
        { breakpoint: 1024, settings: { slidesToShow: 3, slidesToScroll: 3, infinite: true, dots: true } },
        { breakpoint: 600,  settings: { slidesToShow: 2, slidesToScroll: 2 } },
        { breakpoint: 480,  settings: { slidesToShow: 1, slidesToScroll: 1 } },
      ],
    });
  });
}

function initFlowSlide($: any, wrap: HTMLElement) {
  // Target the .flipster element (inside .wpmf_gallery_wrap .wpmf_gallery_box)
  const $container = $(wrap).find('.flipster');
  if (!$container.length || $container.is(':hidden')) return;
  $(wrap).find('.loading_gallery').hide();
  const enableNavButtons = parseInt($container.data('button')) === 1;
  const opts: any = {
    style: 'coverflow',
    spacing: 0,
    loop: true,
    autoplay: 5000,
    onItemSwitch: function(currentItem: any) {
      $container.find('.flipster__container').height($(currentItem).height());
    },
    onItemStart: function(currentItem: any) {
      $container.find('.flipster__container').height($(currentItem).height());
    },
  };
  if (enableNavButtons) {
    opts.buttons = 'custom';
    opts.buttonNext = '<i class="flipto-next material-icons"> keyboard_arrow_right </i>';
    opts.buttonPrev = '<i class="flipto-prev material-icons"> keyboard_arrow_left </i>';
  }
  if (typeof $.fn.flipster !== 'undefined') {
    $container.flipster(opts);
  }
}

function initCustomGrid($: any, wrap: HTMLElement) {
  const $container = $(wrap).find('.wpmf-custom-grid');
  if (!$container.length) return;
  $(wrap).find('.loading_gallery').hide();
  const gutter = parseInt($container.data('gutter')) || 0;
  const wrapWidth = $container.width();
  const oneColWidth = (wrapWidth - gutter * 11) / 12;

  $container.find('.grid-item').each(function(this: Element) {
    const $item = $(this);
    const dimensions = $item.data('styles');
    const w = (dimensions && typeof dimensions.width !== 'undefined') ? parseInt(dimensions.width) : 2;
    const h = (dimensions && typeof dimensions.height !== 'undefined') ? parseInt(dimensions.height) : 2;
    const g = (w - 1) * gutter;
    let displayWidth = oneColWidth;
    let displayHeight = oneColWidth;
    if (w > 1) displayWidth = oneColWidth * w + g;
    if (w === h) {
      displayHeight = displayWidth;
    } else if (h > 1) {
      displayHeight = oneColWidth * h + (h - 1) * gutter;
    }
    $item.width(displayWidth);
    $item.height(displayHeight);
    $item.css('opacity', 1);
  });

  if (typeof $.fn.isotope !== 'undefined') {
    $container.isotope({
      itemSelector: '.grid-item',
      layoutMode: 'packery',
      resizable: true,
      initLayout: true,
      packery: { gutter: gutter },
    });
  }
}

function initGalleryAddonRuntime(win: any, wrap: HTMLElement) {
  const $ = win?.jQuery;
  if (!$) return false;

  const $wrap = $(wrap);
  const hasGalleryRuntime = typeof win.wpmfGallery !== 'undefined' && typeof win.wpmfGallery.initGallery === 'function';
  const hasTreeRuntime = typeof win.wpmfGalleryTree !== 'undefined' && typeof win.wpmfGalleryTree.initModule === 'function';

  if (!hasGalleryRuntime && !hasTreeRuntime) {
    return false;
  }

  if (hasGalleryRuntime) {
    win.wpmfGallery.initGallery(false);
  }

  if (hasTreeRuntime) {
    $wrap.find('.wpmf_gallery_tree').each(function(this: HTMLElement) {
      win.wpmfGalleryTree.initModule($(this));
    });

    const hashInfo = parseGalleryHash(win.location?.hash || '');
    $wrap.find('.wpmf_gallery_tree').each(function(this: HTMLElement) {
      const $tree = $(this);
      const topGalleryId = String($tree.data('id') ?? '');
      const selectedId = hashInfo && hashInfo.topGalleryId === topGalleryId
        ? hashInfo.galleryId
        : String(win.wpmfGalleryTree.getGalleryIDStart($tree) ?? topGalleryId);

      const hasVisibleLoader = $wrap.find('.loading_gallery:visible').length > 0;
      const hasMedia = $wrap.find('.wpmf-gallery-item').length > 0;
      if (selectedId && (!hasMedia || hasVisibleLoader)) {
        win.wpmfGalleryTree.changeFolder($tree, selectedId, $tree);
        win.wpmfGalleryTree.loadGallery($tree, selectedId, topGalleryId);
      }
    });
  }

  return true;
}
// ───────────────────────────────────────────────────────────────────────────────

/**
 * Gallery Addon Module Edit Component (Divi 5)
 * Renders shortcode preview based on the properties configured in the Divi 5 sidebar.
 */
const GalleryAddonEdit = (props: any): ReactElement => {
  const { attrs, id, name, elements } = props;

  const { fetch, response, isLoading } = useFetch<any>(null);
  const fetchAbortRef = useRef<AbortController>();
  const lastShortcodeRef = useRef<string>('');

  const d = attrs?.module?.innerContent?.desktop?.value ?? {};

  const galleryId           = getFieldString(d.galleryId, '0');
  const theme               = getFieldString(d.theme, 'masonry');
  const layout              = getFieldString(d.layout, 'vertical');
  const rowHeight           = getFieldNumber(d.rowHeight, '200');
  const aspectRatio         = getFieldString(d.aspectRatio, '1_1');
  const columns             = getFieldNumber(d.columns, '3');
  const numberLines         = getFieldNumber(d.numberLines, '1');
  const size                = getFieldString(d.size, 'medium');
  const targetsize          = getFieldString(d.targetsize, 'large');
  const action              = getFieldString(d.action, 'file');
  const orderby             = getFieldString(d.orderby, 'post__in');
  const order               = getFieldString(d.order, 'ASC');
  const gutterwidth         = getFieldNumber(d.gutterwidth, '5');
  const galleryNavigation   = getFieldString(d.galleryNavigation, 'off') === 'on' ? '1' : '0';
  const subGalleriesListing = getFieldString(d.subGalleriesListing, 'off') === 'on' ? '1' : '0';
  const galleryImageTags    = getFieldString(d.galleryImageTags, 'off') === 'on' ? '1' : '0';
  const downloadAll         = getFieldString(d.downloadAll, 'off') === 'on' ? '1' : '0';
  const borderRadius        = getFieldNumber(d.borderRadius, '0');
  const borderStyle         = getFieldString(d.borderStyle, 'solid');
  const borderWidth         = getFieldNumber(d.borderWidth, '0');
  const borderColor         = getColorField(d.borderColor, '#cccccc');
  const enableShadow        = getFieldString(d.enableShadow, 'off') === 'on';
  const shadowColor         = getColorField(d.shadowColor, '#cccccc');
  const shadowHorizontal    = getFieldNumber(d.shadowHorizontal, '0');
  const shadowVertical      = getFieldNumber(d.shadowVertical, '0');
  const shadowBlur          = getFieldNumber(d.shadowBlur, '0');
  const shadowSpread        = getFieldNumber(d.shadowSpread, '0');
  const disableOverlay      = getFieldString(d.disableOverlay, 'off') === 'on' ? '1' : '0';
  const hoverColor          = getColorField(d.hoverColor, '#000000');
  const hoverOpacity        = getFieldNumber(d.hoverOpacity, '0.4');
  const hoverTitlePosition  = getFieldString(d.hoverTitlePosition, 'center_center');
  const hoverTitleSize      = getFieldNumber(d.hoverTitleSize, '16');
  const hoverTitleColor     = getColorField(d.hoverTitleColor, '#ffffff');
  const hoverDescPosition   = getFieldString(d.hoverDescPosition, 'none');
  const hoverDescSize       = getFieldNumber(d.hoverDescSize, '14');
  const hoverDescColor      = getColorField(d.hoverDescColor, '#ffffff');
  const previewSelector     = `wpmf-gallery-preview-${String(id ?? galleryId).replace(/[^a-zA-Z0-9_-]/g, '-')}`;

  // Build shortcode and fetch preview whenever relevant attrs change
  useEffect(() => {
    if (galleryId === '0' || galleryId === '') {
      return;
    }

    const imgShadow = enableShadow
      ? `${shadowHorizontal}px ${shadowVertical}px ${shadowBlur}px ${shadowSpread}px ${shadowColor}`
      : '';

    const shortcode = `[wpmfgallery`
      + ` is_divi="1"`
      + ` is_lazy_load="0"`
      + ` selector="${previewSelector}"`
      + ` gallery_id="${galleryId}"`
      + ` display="${theme}"`
      + ` layout="${layout}"`
      + ` row_height="${rowHeight}"`
      + ` aspect_ratio="${aspectRatio}"`
      + ` columns="${columns}"`
      + ` number_lines="${numberLines}"`
      + ` size="${size}"`
      + ` targetsize="${targetsize}"`
      + ` link="${action}"`
      + ` wpmf_orderby="${orderby}"`
      + ` wpmf_order="${order}"`
      + ` gutterwidth="${gutterwidth}"`
      + ` display_tree="${galleryNavigation}"`
      + ` sub_galleries_listing="${subGalleriesListing}"`
      + ` display_tag="${galleryImageTags}"`
      + ` download_all="${downloadAll}"`
      + ` img_border_radius="${borderRadius}"`
      + ` border_style="${borderStyle}"`
      + ` border_width="${borderWidth}"`
      + ` border_color="${borderColor}"`
      + ` img_shadow="${imgShadow}"`
      + ` disable_overlay="${disableOverlay}"`
      + ` hover_color="${hoverColor}"`
      + ` hover_opacity="${hoverOpacity}"`
      + ` hover_title_position="${hoverTitlePosition}"`
      + ` hover_title_size="${hoverTitleSize}"`
      + ` hover_title_color="${hoverTitleColor}"`
      + ` hover_desc_position="${hoverDescPosition}"`
      + ` hover_desc_size="${hoverDescSize}"`
      + ` hover_desc_color="${hoverDescColor}"`
      + `]`;

    if (shortcode === lastShortcodeRef.current) {
      return;
    }
    lastShortcodeRef.current = shortcode;

    if (fetchAbortRef.current) {
      fetchAbortRef.current.abort();
    }
    fetchAbortRef.current = new AbortController();

    fetch({
      restRoute: `/wp/v2/wpmf-block-preview?shortcode=${encodeURIComponent(shortcode)}`,
      method: 'GET',
      signal: fetchAbortRef.current.signal,
    }).catch((error: any) => {
      if (error?.name === 'AbortError') return;
      console.error(error);
    });

    return () => {
      if (fetchAbortRef.current) {
        fetchAbortRef.current.abort();
      }
    };
  }, [
    galleryId, theme, layout, rowHeight, aspectRatio, columns, numberLines, size,
    targetsize, action, orderby, order, gutterwidth, galleryNavigation,
    subGalleriesListing, galleryImageTags, downloadAll,
    borderRadius, borderStyle, borderWidth, borderColor,
    enableShadow, shadowColor, shadowHorizontal, shadowVertical, shadowBlur, shadowSpread,
    disableOverlay, hoverColor, hoverOpacity,
    hoverTitlePosition, hoverTitleSize, hoverTitleColor,
    hoverDescPosition, hoverDescSize, hoverDescColor
  ]);

  const containerRef = useRef<HTMLDivElement>(null);

  // Initialize gallery themes after HTML is injected.
  // This mirrors the exact pattern used in the Divi 4 gallery addon (builder-bundle.min.js):
  // - Use setInterval to poll for the rendered DOM elements
  // - Hide .loading_gallery spinner
  // - Use $.fn.imagesLoaded (jQuery plugin method, NOT the global imagesLoaded function)
  // - Then initialize masonry / slick
  useEffect(() => {
    if (!response?.html || !containerRef.current) return;

    const wrap = containerRef.current;

    const interval = setInterval(() => {
      const doc = wrap.ownerDocument;
      const win = doc?.defaultView as any;
      if (!win || typeof win.jQuery === 'undefined') return;
      const $ = win.jQuery;

      $(wrap).find('.loading_gallery').hide();

      if (initGalleryAddonRuntime(win, wrap)) {
        clearInterval(interval);
        return;
      }

      if ((theme === 'masonry' || theme === 'portfolio') && $(wrap).find('.gallery-masonry').length) {
        clearInterval(interval);
        initMasonry($, wrap);
      } else if (theme === 'slider' && $(wrap).find('.wpmfslick').length) {
        clearInterval(interval);
        initSlider($, wrap, numberLines);
      } else if (theme === 'flowslide' && $(wrap).find('.flipster').length) {
        clearInterval(interval);
        initFlowSlide($, wrap);
      } else if (theme === 'custom_grid' && $(wrap).find('.wpmf-custom-grid').length) {
        clearInterval(interval);
        initCustomGrid($, wrap);
      } else if (theme !== 'masonry' && theme !== 'portfolio' && theme !== 'slider' && theme !== 'flowslide' && theme !== 'custom_grid') {
        // Default / square_grid / material — no special JS needed
        clearInterval(interval);
      }
    }, 200);

    return () => clearInterval(interval);
  }, [response?.html, theme]);

  const hasGallery = galleryId !== '0' && galleryId !== '';

  return (
    <ModuleContainer 
      attrs={attrs} 
      elements={elements} 
      id={id} 
      name={name}
      stylesComponent={(styleProps: any) => (
        <StyleContainer mode={styleProps.mode} state={styleProps.state}>
          {elements.style({ attrName: 'module' })}
        </StyleContainer>
      )}
    >
      {elements.styleComponents({ attrName: 'module' })}
      <div className="wpmf-divi5-module-preview" ref={containerRef}>
        {/* Shortcode Preview */}
        {!hasGallery ? (
          <div style={{ backgroundColor: '#f0f0f0', padding: '20px', textAlign: 'center', border: '2px dashed #ccc', borderRadius: '4px' }}>
            <strong>WPMF Gallery Addon</strong>
            <p style={{ margin: '8px 0 0', fontSize: '13px', color: '#666' }}>
              Select a gallery in the settings panel to display a preview.
            </p>
          </div>
        ) : isLoading ? (
          <div style={{ backgroundColor: '#fafafa', padding: '20px', textAlign: 'center', border: '1px solid #ccc' }}>
            <strong>Loading Gallery Addon Preview...</strong>
          </div>
        ) : response?.html ? (
          <div dangerouslySetInnerHTML={{ __html: response.html }} />
        ) : null}
      </div>
    </ModuleContainer>
  );
};

export default GalleryAddonEdit;
