<?php // https://divibooster.com/set-a-custom-counter-duration-in-the-divi-number-counter-module/
namespace DiviBooster\DiviBooster\Modules\NumberCounter\CounterDuration;

const DIVI4_MODULE_SLUG = 'et_pb_number_counter';
const DIVI5_MODULE_SLUG = 'divi/number-counter';
const DIVI4_SETTING_SLUG = 'divibooster_counter_duration';
const DIVI5_SETTING_SLUG = 'diviboosterCounterDuration';
const FRONTEND_JS_HANDLE = 'divibooster_number_counter_duration';

// === Divi 4: Field Registration ===
add_filter('et_pb_all_fields_unprocessed_' . DIVI4_MODULE_SLUG, __NAMESPACE__ . '\\add_divi4_field');
function add_divi4_field($fields) {
    if (!is_array($fields)) return $fields;
  $fields[DIVI4_SETTING_SLUG] = [
    'label'           => 'Counter Duration',
    'type'            => 'range',
    'option_category' => 'configuration',
    'description'     => 'Set how long the number animation takes (in milliseconds).',
    'default'         => 1800,
    'range_settings'  => array(
        'min'             => 0,
        'max'             => 10000,
        'step'            => 100,
    ),
    'toggle_slug'     => 'main_content',
    'tab_slug'        => 'general',
    'default_on_front'=> '',
    'vb_support'      => true,
  ];
    return $fields;
}

// === Divi 5: Attribute Registration (PHP Fallback) ===
add_filter('divi_module_library_register_module_attrs', function($module_attrs, $filter_args) {
    if (($filter_args['name'] ?? '') !== DIVI5_MODULE_SLUG) {
        return $module_attrs;
    }
    $module_attrs[DIVI5_SETTING_SLUG] = get_divi5_attribute_definition();
    return $module_attrs;
}, 10, 2);

function get_divi5_attribute_definition() {
  return [
    'type'     => 'object',
    'settings' => [
      'innerContent' => [
        'groupType' => 'group-items',
        'items'     => [
          'diviboosterCounterDurationField' => [
            'groupSlug'   => 'contentText',
            'attrName'    => DIVI5_SETTING_SLUG,
            'label'       => 'Counter Duration',
            'description' => 'Set how long the number animation takes (in milliseconds).',
            'features'    => [
              'hover'      => false,
              'sticky'     => false,
              'responsive' => false,
              'preset'     => 'advanced',
            ],
            'render'      => true,
            'priority'    => 110,
            'component'   => [
              'type' => 'field',
              'name' => 'divi/range',
              'props' => [
                'min' => 0,
                'max' => 10000,
                'step' => 100,
                "allowedUnits" => [],
                "defaultUnit" => ""
              ],
            ],
            'defaultAttr' => [ 'desktop' => [ 'value' => 1800 ] ],
          ],
        ],
      ],
    ],
  ];
}

// === Divi 5: Attribute Mapping & D4â†’D5 Conversion (Inline JS) ===
add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\enqueue_divi5_mapping_js');
function enqueue_divi5_mapping_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 . '-' . DIVI5_SETTING_SLUG . '-mapping');
    \dbdb_enqueue_inline_script_if_dependencies_available($handle, get_divi5_mapping_inline_js(), array('lodash', array('divi-vendor-wp-hooks', 'wp-hooks')));
}

function get_divi5_mapping_inline_js() {
    $attribute_json = wp_json_encode(get_divi5_attribute_definition());
    $divi4_slug = wp_json_encode(DIVI4_MODULE_SLUG);
    $divi5_setting_slug = wp_json_encode(DIVI5_SETTING_SLUG);
    $divi4_setting_slug = wp_json_encode(DIVI4_SETTING_SLUG);
    return <<<END
// Adds the custom attribute to the Number Counter module.
window.vendor.wp.hooks.addFilter('divi.moduleLibrary.moduleAttributes.divi.number-counter', 'divi', (attributes, metadata) => {
    attributes[{$divi5_setting_slug}] = {$attribute_json};
    return attributes;
});

// Map Divi 4 field to Divi 5 attribute for conversion
window.vendor.wp.hooks.addFilter('divi.moduleLibrary.conversion.moduleConversionOutline', 'divi', (conversionOutline, name) => {
    if (name !== {$divi4_slug}) return conversionOutline;
    if (!conversionOutline.module) conversionOutline.module = {};
    conversionOutline.module[{$divi4_setting_slug}] = {$divi5_setting_slug} + '.*';
    return conversionOutline;
});
END;
}

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

// === Frontend JS Registration (once) ===
add_action('wp_enqueue_scripts', __NAMESPACE__ . '\\register_frontend_js');
function register_frontend_js() {
    $js = <<<'END'
(function(){
  function parseMs(val){
    if (val === undefined || val === null) return null;
    if (typeof val === 'number') return val < 0 ? 0 : Math.floor(val);
    var s = String(val).trim();
    if (s === '') return null;
    s = s.replace(/[^0-9\-]/g, '');
    if (s === '' || s === '-' ) return null;
    var n = parseInt(s, 10);
    if (isNaN(n)) return null;
    return n < 0 ? 0 : n;
  }
  function parseNum(str){
    if (typeof str !== 'string') str = String(str || '');
    str = str.replace(/[^0-9+\-\.]/g, '');
    var n = parseFloat(str);
    return isNaN(n) ? 0 : n;
  }

  function applyDuration(wrapper){
    var attempts = 0;
    var maxAttempts = 120; // ~6s window similar to other features
    var msAttr = wrapper.getAttribute('data-divibooster-duration');
    var ms = parseMs(msAttr);
    if (ms === null) return; // use default, nothing to do

    var valueEl = wrapper.querySelector('.percent .percent-value');
    var startAttr = valueEl ? valueEl.getAttribute('data-divibooster-initial-value') : null;
    var start = (startAttr !== null) ? parseNum(startAttr) : 0;
    if (isNaN(start)) start = 0;
    var targetAttr = valueEl ? valueEl.getAttribute('data-divibooster-target-value') : null;
    var targetSrc = wrapper.getAttribute('data-number-value') || targetAttr || (valueEl ? valueEl.textContent : '0');
    var target = parseNum(targetSrc);
    if (valueEl) {
      var currentVal = parseFloat(valueEl.textContent);
      if (isNaN(currentVal)) {
        valueEl.textContent = String(start || 0);
      }
    }

    function tryApply(){
      attempts++;
      var $ = window.jQuery;
      if ($){
        var $percent = $(wrapper).find('.percent');
        var chart = $percent.data('easyPieChart') || $(wrapper).data('easyPieChart');
        if (chart){
          var opts = chart.options || (chart.options = {});
          var prevAnimate = opts.animate;

          // Only disable when duration <= 0. Do not infer equality from labels in Divi 5.
          if (ms <= 0) {
            if (prevAnimate && typeof prevAnimate === 'object') {
              prevAnimate.enabled = false;
            } else {
              opts.animate = false;
            }
          } else {
            if (prevAnimate && typeof prevAnimate === 'object') {
              prevAnimate.duration = ms;
              prevAnimate.enabled = true;
            } else if (typeof prevAnimate === 'number') {
              opts.animate = ms;
            } else if (prevAnimate === true) {
              opts.animate = { duration: ms, enabled: true };
            } else if (prevAnimate === false) {
              // keep disabled as requested
            } else {
              // unknown shape, fall back to numeric which both versions accept
              opts.animate = ms;
            }
          }

          if ((ms <= 0) && typeof chart.disableAnimation === 'function') {
            chart.disableAnimation();
          } else if (ms > 0 && typeof chart.enableAnimation === 'function') {
            chart.enableAnimation();
          }
          return true;
        }
      }
      if (attempts < maxAttempts){ setTimeout(tryApply, 50); }
      return false;
    }

    tryApply();
  }

  function initInstance(wrapper){
    if (!wrapper || wrapper.__dbiv_ncdur_init) return;
    applyDuration(wrapper);
    setTimeout(function(){
      var el = wrapper.querySelector('.percent .percent-value');
      if (el && (el.textContent === 'NaN' || isNaN(parseFloat(el.textContent)))){
        var t = wrapper.getAttribute('data-number-value');
        var n = parseFloat(t);
        el.textContent = String(isFinite(n) ? n : 0);
      }
    }, 150);
    wrapper.__dbiv_ncdur_init = true;
  }

  function initAll(root){
    root = root || document;
    var nodes = root.querySelectorAll('.dbiv-ncdur');
    nodes.forEach(initInstance);
  }

  if (document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', function(){ initAll(document); });
  } else {
    initAll(document);
  }

  if (window.MutationObserver){
    var mo = new MutationObserver(function(muts){
      muts.forEach(function(m){
        if (m.type === 'childList'){
          m.addedNodes && m.addedNodes.forEach(function(node){
            if (node.nodeType === 1){
              if (node.classList && node.classList.contains('dbiv-ncdur')){
                initAll(node);
              }
              var inner = node.querySelectorAll ? node.querySelectorAll('.dbiv-ncdur') : [];
              inner.forEach(initInstance);
            }
          });
        }
      });
    });
    mo.observe(document.documentElement, {childList: true, subtree: true});
  }
})();
END;
    // Load early (in head) so we can affect easyPieChart before Divi triggers animations.
    wp_register_script(FRONTEND_JS_HANDLE, '', [], null, false);
    wp_add_inline_script(FRONTEND_JS_HANDLE, $js);
}

// === Shared: Process Output ===
function process_number_counter_duration_output($content, $duration_raw) {
    if (!is_string($content)) return $content;
    $duration = sanitize_duration($duration_raw);
    if ($duration === null) return $content; // empty -> default behavior

    // Inject data-divibooster-duration into the first wrapper with et_pb_number_counter
    $content = preg_replace_callback(
        '#(<[^>]*class="[^"]*\bet_pb_number_counter\b[^"]*"[^>]*)(>)#',
        function($m) use ($duration) {
            $attr = ' data-divibooster-duration="' . esc_attr((string)$duration) . '"';
            if (strpos($m[0], 'data-divibooster-duration') !== false) {
                return $m[0];
            }
            return $m[1] . $attr . $m[2];
        },
        $content,
        1
    );

    // Add feature class to wrapper to allow JS to target instances
    $content = add_wrapper_class($content, 'dbiv-ncdur');

    // Ensure feature JS is enqueued only if the feature is present in the output
    if (strpos($content, 'dbiv-ncdur') !== false && !wp_script_is(FRONTEND_JS_HANDLE, 'enqueued')) {
        wp_enqueue_script(FRONTEND_JS_HANDLE);
    }

    return $content;
}

function sanitize_duration($value) {
    if ($value === null) return null;
    if (is_string($value)) {
        $trim = trim($value);
        if ($trim === '') return null; // empty -> use default
        $value = preg_replace('/[^0-9\-]/', '', $trim);
        if ($value === '' || $value === '-') return null;
        $value = (int) $value;
    }
    if (is_float($value)) $value = (int) floor($value);
    if (!is_int($value)) {
        return null;
    }
    if ($value < 0) $value = 0;
    return $value;
}

function add_wrapper_class($html, $class_to_add) {
    return preg_replace(
        '#(<[^>]+class=")([^\"]*\bet_pb_number_counter\b[^\"]*)(")#',
        '$1$2 ' . $class_to_add . '$3',
        $html,
        1
    );
}

// === Divi 4: Output Filter ===
add_filter('et_module_shortcode_output', function($output, $render_slug, $module) {
    if (!is_string($output) || $render_slug !== DIVI4_MODULE_SLUG || !isset($module->props) || !is_array($module->props)) {
        return $output;
    }
    $duration = isset($module->props[DIVI4_SETTING_SLUG]) ? $module->props[DIVI4_SETTING_SLUG] : '';
    return process_number_counter_duration_output($output, $duration);
}, 10, 3);

// === Divi 5: Output Filter ===
add_filter('render_block_' . DIVI5_MODULE_SLUG, function($block_content, $parsed_block, $block) {
    $attrs = isset($parsed_block['attrs']) && is_array($parsed_block['attrs']) ? $parsed_block['attrs'] : [];
    $duration = null;
    if (isset($attrs[DIVI5_SETTING_SLUG])) {
        if (isset($attrs[DIVI5_SETTING_SLUG]['desktop']['value'])) {
            $duration = $attrs[DIVI5_SETTING_SLUG]['desktop']['value'];
        } elseif (isset($attrs[DIVI5_SETTING_SLUG]['value'])) {
            $duration = $attrs[DIVI5_SETTING_SLUG]['value'];
        }
    }
    return process_number_counter_duration_output($block_content, $duration);
}, 10, 3);

// Created at 1756532570.

