<?php
namespace DiviBooster\DiviBooster\Modules\Gallery\Masonry;

// === Constants ===
const DIVI4_MODULE_SLUG   = 'et_pb_gallery';
const DIVI4_LAYOUT_FIELD  = 'fullwidth';
const DIVI4_MASONRY_SLUG  = 'dbdb_masonry'; // Unlikely to conflict
const DIVI4_MASONRY_LABEL = 'Masonry';

const DIVI5_MODULE_SLUG   = 'divi/gallery';

// === Divi 4: Add Masonry layout option to Gallery module ===
add_filter('et_pb_all_fields_unprocessed_' . DIVI4_MODULE_SLUG, __NAMESPACE__ . '\\add_masonry_layout_option');
function add_masonry_layout_option($fields) {
    if (!is_array($fields)) {
        return $fields;
    }

    if (!isset($fields[DIVI4_LAYOUT_FIELD]['options'])) {
        return $fields;
    }
    // Add Masonry option if missing
    if (!isset($fields[DIVI4_LAYOUT_FIELD]['options'][DIVI4_MASONRY_SLUG])) {
        $fields[DIVI4_LAYOUT_FIELD]['options'][DIVI4_MASONRY_SLUG] = esc_html__(DIVI4_MASONRY_LABEL, 'et_builder');
    }
    // Sort options alphabetically
    if (is_array($fields[DIVI4_LAYOUT_FIELD]['options'])) {
        asort($fields[DIVI4_LAYOUT_FIELD]['options'], SORT_NATURAL | SORT_FLAG_CASE);
    }

    // Append note to description (front-end only preview)
    $desc_note = esc_html__('Select "Masonry" for a responsive masonry layout (preview only visible on front-end, not builder).', 'et_builder');
    if (empty($fields[DIVI4_LAYOUT_FIELD]['description']) || strpos($fields[DIVI4_LAYOUT_FIELD]['description'], 'Masonry') === false) {
        $existing = isset($fields[DIVI4_LAYOUT_FIELD]['description']) ? trim($fields[DIVI4_LAYOUT_FIELD]['description']) : '';
        $fields[DIVI4_LAYOUT_FIELD]['description'] = trim(($existing ? ($existing . ' ') : '') . $desc_note);
    }

    // Ensure Image Count, Pagination, and Show Title & Caption visible for masonry + grid
    foreach (['posts_number', 'show_pagination', 'show_title_and_caption'] as $field_key) {
        if (!isset($fields[$field_key])) continue;
        if (!isset($fields[$field_key]['show_if'])) {
            $fields[$field_key]['show_if'] = [];
        }
        if (!isset($fields[$field_key]['show_if'][DIVI4_LAYOUT_FIELD])) {
            $fields[$field_key]['show_if'][DIVI4_LAYOUT_FIELD] = ['off', DIVI4_MASONRY_SLUG];
        } else {
            $current = $fields[$field_key]['show_if'][DIVI4_LAYOUT_FIELD];
            if (is_array($current)) {
                if (!in_array(DIVI4_MASONRY_SLUG, $current, true)) {
                    $fields[$field_key]['show_if'][DIVI4_LAYOUT_FIELD][] = DIVI4_MASONRY_SLUG;
                }
            } else {
                if ($current !== DIVI4_MASONRY_SLUG) {
                    $fields[$field_key]['show_if'][DIVI4_LAYOUT_FIELD] = [$current, DIVI4_MASONRY_SLUG];
                }
            }
        }
    }

    return $fields;
}

// === Shared helpers (Divi 4 & 5) ===
function extract_order_class_from_html($html) {
    if (!is_string($html) || $html === '') return '';
    if (!preg_match('/<div[^>]*class=\"([^\"]*\bet_pb_gallery\b[^\"]*)\"/i', $html, $m)) {
        return '';
    }
    $classes = preg_split('/\s+/', $m[1], -1, PREG_SPLIT_NO_EMPTY);
    foreach ($classes as $c) {
        if (preg_match('/^et_pb_gallery_\d+(?:_[^\s]+)?$/', $c)) {
            return $c;
        }
    }
    if (preg_match('/et_pb_gallery_\d+(?:_[^\s]+)?/', $m[1], $m2)) {
        return $m2[0];
    }
    return '';
}

function add_masonry_indicator_class_to_wrapper($content) {
    return preg_replace(
        '/(<div\s+class=\"[^\"]*et_pb_gallery[^\"]*)\"/i',
        '$1 divibooster-gallery-masonry"',
        $content,
        1
    );
}

function sanitize_img_srcset_cropped_sizes($html) {
    return preg_replace_callback(
        '/<img([^>]+)srcset=\"([^\"]+)\"([^>]*)>/i',
        function ($matches) {
            $before = $matches[1];
            $srcset = $matches[2];
            $after  = $matches[3];
            $sources = array_map('trim', explode(',', $srcset));
            $filtered = array_filter($sources, function ($src) {
                $url = trim(explode(' ', $src)[0]);
                $url_no_query = preg_replace('/\?.*$/', '', $url);
                return !preg_match('/-\d+x\d+(?=\.[a-zA-Z]{2,5}$)/', $url_no_query);
            });
            $new_srcset = $filtered ? implode(', ', $filtered) : $srcset;
            return '<img' . $before . 'srcset="' . esc_attr($new_srcset) . '"' . $after . '>';
        },
        $html
    );
}

function build_masonry_css($order_class) {
    if ($order_class === '') return '';
    $cls = '.' . $order_class . '.divibooster-gallery-masonry';
    $gap = 15; // px column gap
    // Container: disable grid/flex from Divi 5, apply CSS columns and ensure full width
    $css = "{$cls} .et_pb_gallery_items{display:block !important;column-count:3;column-gap:{$gap}px;width:100% !important;max-width:100% !important;grid-template-columns:unset !important;grid-auto-rows:unset !important;align-items:unset !important;}";
    $css .= "@media only screen and (max-width:1200px){ {$cls} .et_pb_gallery_items{column-count:2;} }";
    $css .= "@media only screen and (max-width:767px){ {$cls} .et_pb_gallery_items{column-count:1;} }";
    // Items: prevent column breaks and neutralize flex/grid sizing from theme
    $css .= "{$cls} .et_pb_gallery_items .et_pb_gallery_item,{$cls} .et_pb_gallery_items > li,{$cls} .et_pb_gallery_items > div{break-inside:avoid;page-break-inside:avoid;-webkit-column-break-inside:avoid;-moz-column-break-inside:avoid;width:100% !important;max-width:100% !important;margin:0 0 16px 0 !important;float:none !important;display:inline-block !important;flex:0 0 auto !important;}";
    // Inner elements: ensure media scales to the item width
    $css .= "{$cls} .et_pb_gallery_items .et_pb_gallery_item .et_pb_gallery_image,{$cls} .et_pb_gallery_items .et_pb_gallery_item .et_pb_gallery_title{max-width:100% !important;width:100% !important;}";
    $css .= "{$cls} .et_pb_gallery_items .et_pb_gallery_item .et_pb_gallery_image img{width:100% !important;height:auto !important;display:block;}";
    // List reset (in case UL is used)
    $css .= "{$cls} .et_pb_gallery_items{list-style:none;margin-left:0;padding-left:0;}";
    $css .= "{$cls} .et_pb_gallery_pagination { display: none !important; }";
    return $css;
}

function should_enable_masonry_from_divi4_props($props) {
    $layout = isset($props[DIVI4_LAYOUT_FIELD]) ? $props[DIVI4_LAYOUT_FIELD] : '';
    return ($layout === DIVI4_MASONRY_SLUG);
}

function should_enable_masonry_from_divi5_attrs($attrs) {
    // Support several shapes: direct 'fullwidth', or nested 'module' -> 'advanced' -> 'fullwidth' with desktop/value
    if (isset($attrs[DIVI4_LAYOUT_FIELD]) && $attrs[DIVI4_LAYOUT_FIELD] === DIVI4_MASONRY_SLUG) {
        return true;
    }
    // Nested path
    $v = null;
    if (isset($attrs['module']['advanced']['fullwidth']['desktop']['value'])) {
        $v = $attrs['module']['advanced']['fullwidth']['desktop']['value'];
    } elseif (isset($attrs['module']['advanced']['fullwidth']['value'])) {
        $v = $attrs['module']['advanced']['fullwidth']['value'];
    }
    return ($v === DIVI4_MASONRY_SLUG);
}

// === Divi 4: Apply Masonry classes and output the required styles/scripts ===
add_filter('et_module_shortcode_output', __NAMESPACE__ . '\\gallery_module_masonry_output', 10, 3);
function gallery_module_masonry_output($output, $render_slug, $module) {
    if (!is_string($output) || $render_slug !== DIVI4_MODULE_SLUG || !isset($module->props)) {
        return $output;
    }
    if (!should_enable_masonry_from_divi4_props($module->props)) {
        return $output;
    }
    // Extract order class from HTML
    $order_class = extract_order_class_from_html($output);
    if ($order_class === '') {
        return $output;
    }

    // Add indicator class to wrapper
    $output = add_masonry_indicator_class_to_wrapper($output);

    // Remove cropped sizes from srcset
    $output = sanitize_img_srcset_cropped_sizes($output);

    // Append scoped CSS for this instance
    $css = build_masonry_css($order_class);
    if ($css !== '') {
        $output .= '<style>' . $css . '</style>';
    }

    return $output;
}

// === Divi 5: Front-end render filter ===
add_filter('render_block_' . DIVI5_MODULE_SLUG, __NAMESPACE__ . '\\divi5_gallery_masonry_render', 10, 3);
function divi5_gallery_masonry_render($block_content, $parsed_block, $block) {
    if (!is_string($block_content)) {
        return $block_content;
    }
    $attrs = isset($parsed_block['attrs']) && is_array($parsed_block['attrs']) ? $parsed_block['attrs'] : [];
    if (!should_enable_masonry_from_divi5_attrs($attrs)) {
        return $block_content;
    }

    $order_class = extract_order_class_from_html($block_content);
    if ($order_class === '') {
        return $block_content;
    }

    // Add indicator class + sanitize srcset
    $block_content = add_masonry_indicator_class_to_wrapper($block_content);
    $block_content = sanitize_img_srcset_cropped_sizes($block_content);

    // Append per-instance CSS
    $css = build_masonry_css($order_class);
    if ($css !== '') {
        $block_content .= '<style>' . $css . '</style>';
    }

    return $block_content;
}

// === Divi 5: Visual Builder (JS) - Add Masonry to Layout options + conversion mapping + field visibility tweaks ===
add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\enqueue_divi5_vb_js');
function enqueue_divi5_vb_js() {
    if ((!function_exists('et_builder_d5_enabled') || !\et_builder_d5_enabled()) ||
        (!function_exists('et_core_is_fb_enabled') || !\et_core_is_fb_enabled())) {
        return;
    }
    $handle = sanitize_title('divi-booster-' . DIVI5_MODULE_SLUG . '-masonry-layout');
    wp_register_script($handle, '', ['lodash', 'divi-vendor-wp-hooks'], null, true);
    wp_enqueue_script($handle);
    wp_add_inline_script($handle, get_divi5_inline_js_for_masonry());
}

function get_divi5_inline_js_for_masonry() {
    $d4slug = wp_json_encode(DIVI4_MODULE_SLUG);
    $d5slug = wp_json_encode(DIVI5_MODULE_SLUG);
    $masonry = wp_json_encode(DIVI4_MASONRY_SLUG);
    $masonryLabel = wp_json_encode(DIVI4_MASONRY_LABEL);
    $descNote = wp_json_encode(__('Select "Masonry" for a responsive masonry layout (preview only visible on front-end, not builder).', 'et_builder'));
    return <<<JS
(function(){
  const hooks = window.vendor?.wp?.hooks;
  if (!hooks) return;

  // Add Masonry option to Layout control and append description note
  hooks.addFilter('divi.moduleLibrary.moduleAttributes.divi.gallery', 'divi', (attributes, metadata) => {
    try {
      // Find the fullwidth field (may be nested under .item)
      const fullwidth =
        attributes?.module?.settings?.advanced?.items?.fullwidth ||
        attributes?.module?.advanced?.fullwidth ||
        attributes?.module?.settings?.advanced?.fullwidth;

      // If fullwidth is a group-item, options are under fullwidth.item.component.props.options
      let optionsObj;
      if (fullwidth?.item?.component?.props?.options) {
        optionsObj = fullwidth.item.component.props.options;
      }

      // Add Masonry option if missing
      if (optionsObj && !optionsObj[{$masonry}]) {
        optionsObj[{$masonry}] = { label: {$masonryLabel} };
      }

      // Sort options alphabetically by label
      if (optionsObj && typeof optionsObj === 'object') {
        const sorted = Object.keys(optionsObj)
          .sort((a, b) => String(optionsObj[a].label).localeCompare(String(optionsObj[b].label)))
          .reduce((o, k) => (o[k] = optionsObj[k], o), {});
        fullwidth.item.component.props.options = sorted;
      }

      // Append description note if not present
      if (
        fullwidth?.item?.description !== undefined &&
        String(fullwidth.item.description).indexOf('Masonry') === -1
      ) {
        fullwidth.item.description =
          String(fullwidth.item.description || '').trim() + ' ' + {$descNote};
      }

      // Field visibility adjustments: show these when fullwidth is off (grid) or masonry
      function addVisibleGuard(item) {
        if (!item) return;
        const prevVisible = item.visible;
        item.visible = function(ctx){
          try {
            const v = ctx?.attrs?.module?.advanced?.fullwidth?.desktop?.value ?? ctx?.attrs?.module?.advanced?.fullwidth?.value;
            const showWhen = (v === 'off' || v === {$masonry});
            return (typeof prevVisible === 'function') ? (prevVisible(ctx) && showWhen) : showWhen;
          } catch(e) { return true; }
        };
      }
      // Try common locations for these items
      const items = attributes?.module?.settings?.innerContent?.items || attributes?.module?.settings?.advanced?.items || {};
      addVisibleGuard(items?.postsNumber || items?.posts_number);
      addVisibleGuard(items?.showPagination || items?.show_pagination);
      addVisibleGuard(items?.showTitleAndCaption || items?.show_title_and_caption);

      // Orientation: keep hidden for masonry
      const orient = items?.orientation;
      if (orient) {
        const prevVisible = orient.visible;
        orient.visible = function(ctx){
          try {
            const v = ctx?.attrs?.module?.advanced?.fullwidth?.desktop?.value ?? ctx?.attrs?.module?.advanced?.fullwidth?.value;
            const notMasonry = (v !== {$masonry});
            return (typeof prevVisible === 'function') ? (prevVisible(ctx) && notMasonry) : notMasonry;
          } catch(e) { return true; }
        };
      }
    } catch(e) {}
    return attributes;
  });

  // Conversion outline: ensure Divi 4 fullwidth maps to Divi 5 module.advanced.fullwidth
  hooks.addFilter('divi.moduleLibrary.conversion.moduleConversionOutline', 'divi', (outline, name) => {
    if (name !== {$d4slug}) return outline;
    if (!outline.module) outline.module = {};
    // Map fullwidth to the D5 path (keep any existing mapping)
    if (!outline.module.fullwidth) outline.module.fullwidth = 'module.advanced.fullwidth.*';
    return outline;
  });
})();
JS;
}

// === Divi 5: PHP conversion outline fallback ===
add_filter('divi.moduleLibrary.conversion.moduleConversionOutline', __NAMESPACE__ . '\\divi5_conversion_outline_masonry', 10, 2);
function divi5_conversion_outline_masonry($conversion_outline, $module_name) {
    if ($module_name !== DIVI5_MODULE_SLUG) {
        return $conversion_outline;
    }
    if (!isset($conversion_outline['module']) || !is_array($conversion_outline['module'])) {
        $conversion_outline['module'] = array();
    }
    if (empty($conversion_outline['module']['fullwidth'])) {
        $conversion_outline['module']['fullwidth'] = 'module.advanced.fullwidth.*';
    }
    return $conversion_outline;
}

// Created at 1759302608.
