<?php

namespace DiviBooster\GlobalGlassmorphismBackgroundBlur;

// === Constants ===
const D4_FIELD_SLUG      = 'divibooster_background_blur';
const D5_ATTR_SLUG       = 'diviboosterBackgroundBlur';
const D4_TOGGLE_SLUG     = 'divibooster_glassmorphism';
const D5_GROUP_SLUG      = 'designGlassmorphism';
const LABEL_BLUR         = 'Blur Strength';
const LABEL_GROUP        = 'Glass Effect';
const RANGE_MIN          = 0;
const RANGE_MAX          = 100;
const RANGE_STEP         = 1;
const DEFAULT_BLUR       = 0; // px

// === Hook Registration ===
if (function_exists('add_filter')) {
    // Divi 4: Add Design group to modules in builder (fields registered via static list)
    \add_filter('et_builder_get_parent_modules', __NAMESPACE__ . '\\divi4_register_on_parent_modules', 50, 2);
    \add_filter('et_builder_get_child_modules', __NAMESPACE__ . '\\divi4_register_on_child_modules', 50, 2);

    // Divi 4: Apply per-instance CSS via builder style store
    \add_filter('et_module_shortcode_output', __NAMESPACE__ . '\\divi4_output', 10, 3);

    // Divi 5: Add attribute to all divi/* blocks at registration time
    \add_filter('block_type_metadata_settings', __NAMESPACE__ . '\\divi5_register_attribute_globally');

    // Divi 5: Map D4 field -> D5 attribute for all modules during conversion
    \add_filter('divi.moduleLibrary.conversion.moduleConversionOutline', __NAMESPACE__ . '\\divi5_register_conversion_outline', 10, 2);

    // Divi 5: Fallback global render_block processor to inject per-instance CSS
    \add_filter('render_block', __NAMESPACE__ . '\\divi5_render_block', 10, 2);
}

if (function_exists('add_action')) {
    // Divi 5: Enqueue VB-only JS to add UI group + field + live preview
    \add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\enqueue_divi5_vb_js');

    // Divi 4: Register field on a static list of module slugs
    \add_action('init', __NAMESPACE__ . '\\divi4_register_static_module_slugs', 20);
}

// === Divi 4: Register on Parent Modules ===
function divi4_register_on_parent_modules($modules, $post_type = '') {
    if (!is_array($modules)) return $modules;
    foreach ($modules as $key => $module) {
        $slug = '';
        if (is_object($module) && isset($module->slug)) {
            $slug = (string) $module->slug;
        } elseif (is_string($key)) {
            $slug = (string) $key;
        }
        if ($slug !== '') {
            divi4_add_group_to_module_object($module);
        }
    }
    return $modules;
}

// === Divi 4: Register on Child Modules ===
function divi4_register_on_child_modules($modules, $post_type = '') {
    if (!is_array($modules)) return $modules;
    foreach ($modules as $key => $module) {
        $slug = '';
        if (is_object($module) && isset($module->slug)) {
            $slug = (string) $module->slug;
        } elseif (is_string($key)) {
            $slug = (string) $key;
        }
        if ($slug !== '') {
            divi4_add_group_to_module_object($module);
        }
    }
    return $modules;
}

function divi4_add_group_to_module_object($module) {
    if (!is_object($module)) return;
    if (!isset($module->settings_modal_toggles) || !is_array($module->settings_modal_toggles)) return;

    if (!isset($module->settings_modal_toggles['advanced'])) {
        $module->settings_modal_toggles['advanced'] = array('toggles' => array());
    }
    if (!isset($module->settings_modal_toggles['advanced']['toggles']) || !is_array($module->settings_modal_toggles['advanced']['toggles'])) {
        $module->settings_modal_toggles['advanced']['toggles'] = array();
    }
    if (!isset($module->settings_modal_toggles['advanced']['toggles'][D4_TOGGLE_SLUG])) {
        $module->settings_modal_toggles['advanced']['toggles'][D4_TOGGLE_SLUG] = array(
            'title'    => LABEL_GROUP,
            'priority' => 100,
        );
    }
}

function divi4_hook_field_for_slug($slug) {
    static $done = array();
    $slug = is_string($slug) ? trim($slug) : (string) $slug;

    // Skip non-module slugs
    $blocked = array('page', 'post', 'project', 'et_pb_layout');
    if ($slug === '' || isset($done[$slug]) || in_array($slug, $blocked, true)) return;

    $done[$slug] = true;

    \add_filter('et_pb_all_fields_unprocessed_' . $slug, function($fields) {
        if (!is_array($fields)) $fields = array();
        $fields[D4_FIELD_SLUG] = array(
            'label'            => esc_html__(LABEL_BLUR, 'divi-booster'),
            'type'             => 'range',
            'option_category'  => 'layout',
            'tab_slug'         => 'advanced',
            'toggle_slug'      => D4_TOGGLE_SLUG,
            'default'          => (string) DEFAULT_BLUR,
            'default_unit'     => 'px',
            'allowed_units'    => array('px'),
            'validate_unit'    => true,
            'mobile_options'   => false,
            'responsive'       => false,
            'hover'            => 'none',
            'sticky'           => false,
            'range_settings'   => array(
                'min'  => (string) RANGE_MIN,
                'max'  => (string) RANGE_MAX,
                'step' => (string) RANGE_STEP,
            ),
            'description'      => esc_html__('Applies a blur to the area behind this element\'s background, creating a frosted glass / glassmorphic effect on semi-transparent backgrounds. This effect shows only on the front-end, not in the visual builder preview.', 'divi-booster'),
        );
        return $fields;
    });
}

// === Divi 4: Register fields on a static list of module slugs ===
function divi4_register_static_module_slugs() {
    //$slugs = array('et_pb_section', 'et_pb_fullwidth_section', 'et_pb_row', 'et_pb_column');

    $slugs = explode(', ', 'et_pb_section, et_pb_row, et_pb_row_inner, et_pb_accordion, et_pb_accordion_item, et_pb_audio, et_pb_counters, et_pb_counter, et_pb_blog, et_pb_blurb, et_pb_button, et_pb_circle_counter, et_pb_code, et_pb_comments, et_pb_contact_form, et_pb_contact_field, et_pb_signup_custom_field, et_pb_countdown_timer, et_pb_cta, et_pb_divider, et_pb_filterable_portfolio, et_pb_fullwidth_code, et_pb_fullwidth_header, et_pb_fullwidth_image, et_pb_fullwidth_map, et_pb_fullwidth_menu, et_pb_fullwidth_portfolio, et_pb_fullwidth_post_content, et_pb_fullwidth_post_slider, et_pb_fullwidth_post_title, et_pb_fullwidth_slider, et_pb_gallery, et_pb_heading, et_pb_icon, et_pb_image, et_pb_login, et_pb_map, et_pb_map_pin, et_pb_menu, et_pb_number_counter, et_pb_portfolio, et_pb_post_content, et_pb_post_slider, et_pb_post_title, et_pb_post_nav, et_pb_pricing_tables, et_pb_pricing_item, et_pb_pricing_table, et_pb_search, et_pb_sidebar, et_pb_signup, et_pb_slider, et_pb_slide, et_pb_social_media_follow, et_pb_social_media_follow_network, et_pb_tabs, et_pb_tab, et_pb_team_member, et_pb_testimonial, et_pb_text, et_pb_toggle, et_pb_video, et_pb_video_slider, et_pb_video_slider_item, et_pb_section, et_pb_row, et_pb_row_inner, et_pb_column, et_pb_column_inner');

    foreach ($slugs as $slug) {
        divi4_hook_field_for_slug($slug);
    }
}

// === Divi 4 Output ===
function divi4_output($output, $render_slug, $module) {
    if (!is_string($output) || !isset($module->props) || !is_array($module->props)) {
        return $output;
    }
    $val = isset($module->props[D4_FIELD_SLUG]) ? $module->props[D4_FIELD_SLUG] : '';
    $blur = sanitize_blur_value($val);
    if ($blur <= 0) {
        return $output;
    }
    if (class_exists('ET_Builder_Element') && is_callable(array('ET_Builder_Element', 'set_style'))) {
        $dec = sprintf('-webkit-backdrop-filter: blur(%1$dpx); backdrop-filter: blur(%1$dpx);', $blur);
        \ET_Builder_Element::set_style($render_slug, array(
            'selector'    => '%%order_class%%',
            'declaration' => $dec,
        ));
    }
    return $output;
}

// === Divi 5: Attribute Registration (all divi/* blocks) ===
function divi5_register_attribute_globally($settings) {
    $module_name       = $settings['name'] ?? '';
    $module_attributes = $settings['attributes'] ?? false;
    if (!is_string($module_name) || strpos($module_name, 'divi/') !== 0) {
        return $settings;
    }
    if (!$module_attributes || !is_array($module_attributes)) {
        return $settings;
    }
    $settings['attributes'][D5_ATTR_SLUG] = get_divi5_attribute_definition();
    return $settings;
}

// === Divi 5: Conversion Mapping (D4 -> D5) ===
function divi5_register_conversion_outline($conversion_outline, $module_name) {
    if (!is_string($module_name) || strpos($module_name, 'divi/') !== 0) {
        return $conversion_outline;
    }
    if (!isset($conversion_outline['module']) || !is_array($conversion_outline['module'])) {
        $conversion_outline['module'] = array();
    }
        $conversion_outline['module'][D4_FIELD_SLUG] = D5_ATTR_SLUG . '.*';
    return $conversion_outline;
}

// === Divi 5: Front-end CSS Injection via render_block ===
function divi5_render_block($block_content, $block) {
    if (!is_string($block_content)) return $block_content;
    $block_name = isset($block['blockName']) ? (string) $block['blockName'] : '';
    if (strpos($block_name, 'divi/') !== 0) return $block_content;

    $attrs = isset($block['attrs']) && is_array($block['attrs']) ? $block['attrs'] : array();
    $blur  = divi5_get_blur_from_attrs($attrs);
    if ($blur <= 0) return $block_content;

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

    $css = build_css_for_order_class($order_class, $blur);
    $block_content .= '<style>' . $css . '</style>';
    return $block_content;
}

// === Divi 5: VB-only JS (UI + live preview) ===
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-divi-global-' . D5_ATTR_SLUG);
    \wp_register_script($handle, '', array('lodash', 'divi-vendor-wp-hooks'), null, true);
    \wp_enqueue_script($handle);
    \wp_add_inline_script($handle, get_divi5_inline_js());
}

function get_divi5_attribute_definition() {
    return [
        'type'     => 'object',
        'settings' => [
            'innerContent' => [
                'groupType' => 'group-items',
                'items'     => [
                    'backgroundBlur' => [
                        'groupSlug'   => D5_GROUP_SLUG,
                        'attrName'    => D5_ATTR_SLUG,
                        'label'       => __(LABEL_BLUR, 'divi-booster'),
                        'description' => __('Applies a blur to the area behind this element\'s background, creating a frosted glass / glassmorphic effect on semi-transparent backgrounds. This effect shows only on the front-end, not in the visual builder preview.', 'divi-booster'),
                        'features'    => [
                            'hover'      => false,
                            'sticky'     => false,
                            'responsive' => false,
                            'preset'     => 'design',
                        ],
                        'render'      => true,
                        'priority'    => 10,
                        'component'   => [
                            'type'  => 'field',
                            'name'  => 'divi/range',
                            'props' => [ 'min' => RANGE_MIN, 'max' => RANGE_MAX, 'step' => RANGE_STEP ],
                        ],
                        'defaultAttr' => [ 'desktop' => [ 'value' => DEFAULT_BLUR ] ],
                    ],
                ],
            ],
        ],
    ];
}

function get_divi5_inline_js() {
    $attr_def = wp_json_encode(get_divi5_attribute_definition());
    $d5attr   = wp_json_encode(D5_ATTR_SLUG);
    $grp      = wp_json_encode(D5_GROUP_SLUG);
    $labelGrp = wp_json_encode(LABEL_GROUP);
    $labelCtl = wp_json_encode(LABEL_BLUR);
    $d4slug   = wp_json_encode(D4_FIELD_SLUG);
    return <<<JS
(function(){
    const hooks  = window.vendor?.wp?.hooks;
    const elem   = window.vendor?.wp?.element;
    if (!hooks) return;

            // Attribute: generic registration for all modules
                hooks.addFilter('divi.moduleLibrary.moduleAttributes', 'divi', (attributes, metadata) => {
    attributes[{$d5attr}] = {$attr_def};
    return attributes;
  });

            // Settings group: attempt generic add for all modules
                hooks.addFilter('divi.moduleLibrary.moduleSettings.groups', 'divi', (groups, metadata) => {
    if (!groups[{$grp}]) {
      groups[{$grp}] = {
        groupName: {$grp},
        panel: 'design',
        priority: 100,
        multiElements: true,
        component: {
          name: 'divi/composite',
          props: { groupLabel: {$labelGrp} }
        }
      };
    }
    return groups;
  });

        // Conversion outline mapping for builder-side conversion
                    hooks.addFilter('divi.moduleLibrary.conversion.moduleConversionOutline', 'divi', (outline, name) => {
    if (!outline.module) outline.module = {};
    outline.module[{$d4slug}] = {$d5attr} + '.*';
    return outline;
  });

  // Live preview: inject/update per-instance style on wrapper render
        hooks.addFilter('divi.module.wrapper.render', 'divi', (moduleWrapper, param) => {
        try {
            const attrs   = param?.attrs || {};
            const v       = attrs?.[{$d5attr}]?.desktop?.value ?? attrs?.[{$d5attr}]?.value ?? 0;
            const n       = parseInt(v, 10) || 0;
            const modName = param?.name || '(unknown)';

            const cls = (moduleWrapper?.props?.className || '');
            const m = cls.match(/(?:^|\s)([A-Za-z0-9_-]*_\d+(?:_[A-Za-z0-9_-]+)*)\b/);
            const orderClass = m ? m[1] : '';
            const dataId = moduleWrapper?.props?.['data-id'] || moduleWrapper?.props?.['data-module-id'] || param?.id || param?.moduleId || '';

            // If no blur, return original wrapper and clean any injected head style and DOM inline styles.
            if (n <= 0) {
                // Clear inline styles on real DOM node (data-id -> orderClass -> edited module fallbacks)
                const clearDom = () => {
                    const esc = (window.CSS && CSS.escape) ? CSS.escape : (s => String(s).replace(/"/g, '\\"'));
                    let target = null;
                    if (dataId) target = document.querySelector('[data-id="' + esc(String(dataId)) + '"]');
                    if (!target && orderClass) target = document.querySelector('.' + orderClass);
                    const base = (modName && modName.indexOf('/') !== -1) ? modName.split('/')[1] : '';
                    const baseClass = base ? ('et_pb_' + base) : '';
                    if (!target && baseClass) target = document.querySelector('.et-vb-module--is-edited.' + baseClass);
                    if (!target) target = document.querySelector('.et-vb-module--is-edited');
                    if (target) {
                        try {
                            target.style.removeProperty && target.style.removeProperty('backdrop-filter');
                            target.style.removeProperty && target.style.removeProperty('-webkit-backdrop-filter');
                        } catch(e) {}
                        target.style.backdropFilter = '';
                        target.style.webkitBackdropFilter = '';
                    }
                };
                if (typeof window !== 'undefined' && window.requestAnimationFrame) window.requestAnimationFrame(clearDom); else setTimeout(clearDom, 0);
                return moduleWrapper;
            }

            // Apply directly to the real DOM node: prefer data-id, then orderClass, then edited-module class
            const base = (modName && modName.indexOf('/') !== -1) ? modName.split('/')[1] : '';
            const baseClass = base ? ('et_pb_' + base) : '';
            const applyDom = () => {
                let target = null;
                const esc = (window.CSS && CSS.escape) ? CSS.escape : (s => String(s).replace(/"/g, '\\"'));
                if (dataId) target = document.querySelector('[data-id="' + esc(String(dataId)) + '"]');
                if (!target && orderClass) target = document.querySelector('.' + orderClass);
                if (!target && baseClass) target = document.querySelector('.et-vb-module--is-edited.' + baseClass);
                if (!target) target = document.querySelector('.et-vb-module--is-edited');
                if (target) {
                    target.style.webkitBackdropFilter = 'blur(' + n + 'px)';
                    target.style.backdropFilter = 'blur(' + n + 'px)';
                }
            };
            if (typeof window !== 'undefined' && window.requestAnimationFrame) {
                window.requestAnimationFrame(applyDom);
            } else {
                setTimeout(applyDom, 0);
            }
            return moduleWrapper;
        } catch(e) { }
        return moduleWrapper;
    });
})();
JS;
}

// === Helpers ===
function sanitize_blur_value($val) {
    if (is_array($val)) {
        // Unexpected structure; treat as 0
        return 0;
    }
    if (!is_string($val)) {
        $val = (string) $val;
    }
    $val = trim($val);
    if ($val === '') return 0;
    // Extract number
    if (preg_match('/-?\d+/', $val, $m)) {
        $num = intval($m[0]);
    } else {
        $num = 0;
    }
    if ($num < RANGE_MIN) $num = RANGE_MIN;
    if ($num > RANGE_MAX) $num = RANGE_MAX;
    return $num;
}

function divi5_get_blur_from_attrs($attrs) {
    if (!is_array($attrs)) return 0;
    if (!isset($attrs[D5_ATTR_SLUG])) return 0;
    $v = $attrs[D5_ATTR_SLUG];
    $val = 0;
    if (is_array($v)) {
        $val = $v['desktop']['value'] ?? $v['value'] ?? 0;
    } else {
        $val = $v;
    }
    return sanitize_blur_value($val);
}

function build_css_for_order_class($order_class, $blur) {
    $b = (int) $blur;
    $selector = '.' . preg_replace('/[^A-Za-z0-9_-]/', '', $order_class);
    return sprintf('%s{-webkit-backdrop-filter:blur(%2$dpx);backdrop-filter:blur(%2$dpx);}', $selector, $b);
}

function extract_order_class_from_html($html) {
    if (!is_string($html) || $html === '') return '';
    if (!preg_match('/class=\"([^\"]+)\"/i', $html, $m)) {
        return '';
    }
    $classes = preg_split('/\s+/', $m[1], -1, PREG_SPLIT_NO_EMPTY);
    foreach ($classes as $c) {
        if (preg_match('/^[A-Za-z0-9_-]+_\d+(?:_[A-Za-z0-9_-]+)?$/', $c)) {
            return $c;
        }
    }
    // Fallback: search entire markup
    if (preg_match('/\b([A-Za-z0-9_-]+_\d+(?:_[A-Za-z0-9_-]+)?)\b/', $html, $m2)) {
        return $m2[1];
    }
    return '';
}

// Created at 1761007493.
