<?php // https://divibooster.com/change-the-filterable-portfolio-module-filter-tab-order/
namespace DiviBooster\DiviBooster\Modules\FilterablePortfolio\TabOrder;

const DIVI5_MODULE_SLUG = 'divi/filterable-portfolio';
const DIVI4_MODULE_SLUG = 'et_pb_filterable_portfolio';
const DIVI5_TAB_ORDER_SLUG = 'diviboosterTabOrder';
const DIVI4_TAB_ORDER_SLUG = 'db_tab_order';
const DIVI5_TAB_ORDER_SLUGS = 'diviboosterTabOrderSlugs';
const DIVI4_TAB_ORDER_SLUGS = 'db_tab_order_slugs';

// === Divi 4: Field Registration ===
add_filter('et_pb_all_fields_unprocessed_' . DIVI4_MODULE_SLUG, __NAMESPACE__ . '\\register_divi4_tab_order_fields');
function register_divi4_tab_order_fields($fields) {
    $fields[DIVI4_TAB_ORDER_SLUG] = [
        'label'            => 'Tab Order',
        'type'             => 'select',
        'option_category'  => 'layout',
        'options'          => [
            'default' => esc_html__('Default', 'et_builder'),
            'random'  => esc_html__('Random',  'et_builder'),
            'reverse' => esc_html__('Reverse', 'et_builder'),
            'by_slug' => esc_html__('By Slug', 'et_builder'),
        ],
        'default'          => 'default',
        'description'      => 'Adjust the order in which filter tabs are displayed.',
        'tab_slug'         => 'advanced',
        'toggle_slug'      => 'layout',
    ];
    $fields[DIVI4_TAB_ORDER_SLUGS] = [
        'label'            => 'Tab Order Slugs',
        'type'             => 'text',
        'option_category'  => 'layout',
        'default'          => '',
        'description'      => 'Enter a comma-separated list of category slugs. These will be displayed in order, before any other categories.',
        'tab_slug'         => 'advanced',
        'toggle_slug'      => 'layout',
        'show_if'          => [
            DIVI4_TAB_ORDER_SLUG => 'by_slug',
        ],
    ];
    return $fields;
}

// === Divi 5: JS Attribute Mapping/Conversion ===
add_action('wp_enqueue_scripts', __NAMESPACE__.'\\enqueue_script');
function enqueue_script() {
    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_TAB_ORDER_SLUG);
    \dbdb_enqueue_inline_script_if_dependencies_available($handle, get_inline_js(), array('lodash', array('divi-vendor-wp-hooks', 'wp-hooks')));
}

function get_inline_js() {
    $attributes = wp_json_encode(get_attribute_definition());
    $divi5_slug = wp_json_encode(DIVI5_MODULE_SLUG);
    $divi4_slug = wp_json_encode(DIVI4_MODULE_SLUG);
    $divi5_tab_order_slug = wp_json_encode(DIVI5_TAB_ORDER_SLUG);
    $divi4_tab_order_slug = wp_json_encode(DIVI4_TAB_ORDER_SLUG);
    $divi5_tab_order_slugs = wp_json_encode(DIVI5_TAB_ORDER_SLUGS);
    $divi4_tab_order_slugs = wp_json_encode(DIVI4_TAB_ORDER_SLUGS);
    return <<<END
window.vendor.wp.hooks.addFilter('divi.moduleLibrary.moduleMapping', 'divi', modules => {
    const path = [{$divi5_slug}, 'metadata', 'attributes'];
    const { set, get, has } = window.lodash;
    const target = get(modules, path) ? get(modules, path) : set(modules, path, {});
    if (has(modules, path)) {
        target[{$divi5_tab_order_slug}] = {$attributes}['tabOrder'];
        target[{$divi5_tab_order_slugs}] = {$attributes}['tabOrderSlugs'];
    }
    return modules;
});
window.vendor.wp.hooks.addFilter('divi.moduleLibrary.conversion.moduleConversionOutline', 'divi', (conversionOutline, name) => {
    if (name !== {$divi4_slug}) return conversionOutline;
    conversionOutline.module[{$divi4_tab_order_slug}] = {$divi5_tab_order_slug} + '.*';
    conversionOutline.module[{$divi4_tab_order_slugs}] = {$divi5_tab_order_slugs} + '.*';
    return conversionOutline;
});
END;
}

add_filter('divi_module_library_register_module_attrs', function($module_attrs, $filter_args) {
    if (($filter_args['name'] ?? '') !== DIVI5_MODULE_SLUG) {
        return $module_attrs;
    }
    $attr_defs = get_attribute_definition();
    $module_attrs[DIVI5_TAB_ORDER_SLUG] = $attr_defs['tabOrder'];
    $module_attrs[DIVI5_TAB_ORDER_SLUGS] = $attr_defs['tabOrderSlugs'];
    return $module_attrs;
}, 10, 2);

// === Divi 5: PHP conversion outline registration ===
function dbdb_register_divi5_tab_order_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_TAB_ORDER_SLUG ]  = DIVI5_TAB_ORDER_SLUG . '.*';
    $conversion_outline['module'][ DIVI4_TAB_ORDER_SLUGS ] = DIVI5_TAB_ORDER_SLUGS . '.*';
    return $conversion_outline;
}
add_filter( 'divi.moduleLibrary.conversion.moduleConversionOutline', __NAMESPACE__ . '\\dbdb_register_divi5_tab_order_conversion', 10, 2 );

function get_attribute_definition() {
    return [
        'tabOrder' => [
            'type'     => 'object',
            'settings' => [
                'innerContent' => [
                    'groupType' => 'group-items',
                    'items'     => [
                        'diviboosterTabOrderSelect' => [
                            'groupSlug'   => 'designLayout',
                            'attrName'    => DIVI5_TAB_ORDER_SLUG,
                            'label'       => 'Tab Order',
                            'description' => 'Adjust the order in which filter tabs are displayed.',
                            'features'    => [
                                'hover'      => false,
                                'sticky'     => false,
                                'responsive' => false,
                                'preset'     => 'advanced',
                            ],
                            'render'   => true,
                            'priority' => 31,
                            'component' => [
                                'type' => 'field',
                                'name' => 'divi/select',
                                'props' => [
                                    'options' => [
                                        'default' => [ 'label' => esc_html__('Default', 'et_builder') ],
                                        'random'  => [ 'label' => esc_html__('Random', 'et_builder') ],
                                        'reverse' => [ 'label' => esc_html__('Reverse', 'et_builder') ],
                                        'by_slug' => [ 'label' => esc_html__('By Slug', 'et_builder') ]
                                    ]
                                ],
                            ],
                            'defaultAttr' => [ 'desktop' => [ 'value' => 'default' ] ],
                        ],
                    ],
                ],
            ],
        ],
        'tabOrderSlugs' => [
            'type'     => 'object',
            'settings' => [
                'innerContent' => [
                    'groupType' => 'group-items',
                    'items'     => [
                        'diviboosterTabOrderSlugsText' => [
                            'groupSlug'   => 'designLayout',
                            'attrName'    => DIVI5_TAB_ORDER_SLUGS,
                            'label'       => 'Tab Order Slugs',
                            'description' => 'Enter a comma-separated list of category slugs. These will be displayed in order, before any other categories.',
                            'features'    => [
                                'hover'      => false,
                                'sticky'     => false,
                                'responsive' => false,
                                'preset'     => 'advanced',
                            ],
                            'render'   => true,
                            'priority' => 32,
                            'component' => [
                                'type' => 'field',
                                'name' => 'divi/text',
                            ],
                            'defaultAttr' => [ 'desktop' => [ 'value' => '' ] ],
                            'showIf' => [
                                DIVI5_TAB_ORDER_SLUG => 'by_slug',
                            ],
                        ],
                    ],
                ],
            ],
        ]
    ];
}

// === Shared: Tab Order Application ===
function apply_tab_order_to_terms($terms, $order_type = 'default', $order_slugs = '') {
    //var_dump($terms, $order_type, $order_slugs);
    if (!is_array($terms)) return $terms;
    if ($order_type === 'reverse') {
        $terms = array_reverse($terms);
    } elseif ($order_type === 'random') {
        shuffle($terms);
    } elseif ($order_type === 'by_slug') {
        if (empty($order_slugs)) return $terms;
        $slugs = array_map('trim', explode(',', $order_slugs));
        $prepend = [];
        $used = [];
        foreach ($slugs as $slug) {
            foreach ($terms as $k=>$term) {
                if (isset($term->slug) && $term->slug === $slug && !in_array($k, $used, true)) {
                    $prepend[] = $term;
                    $used[] = $k;
                    break;
                }
            }
        }
        foreach ($used as $uk) unset($terms[$uk]);
        $terms = array_merge($prepend, $terms);
    }
    return array_values($terms);
}

// === Divi 4: Apply tab order directly via get_terms filter for the module ===
function divi4_get_terms_sort($terms, $taxonomies, $args, $term_query) {
    // Retrieve $atts from global set in divi4_add_tab_order_context
    $atts = $GLOBALS['divibooster_divi4_tab_order_atts'] ?? [];
    $order_type  = $atts[DIVI4_TAB_ORDER_SLUG] ?? 'default';
    $order_slugs = $atts[DIVI4_TAB_ORDER_SLUGS] ?? '';
    return apply_tab_order_to_terms($terms, $order_type, $order_slugs);
}

// To ensure our filter receives the needed context, hook into the module's shortcode attributes filter
add_filter('et_pb_module_shortcode_attributes', __NAMESPACE__ . '\\divi4_add_tab_order_context', 10, 3);
function divi4_add_tab_order_context($props, $atts, $slug) {
    if ($slug !== DIVI4_MODULE_SLUG) return $props;
    // Store $atts in a global variable for access in divi4_get_terms_sort
    $GLOBALS['divibooster_divi4_tab_order_atts'] = $atts;
    add_filter('get_terms', __NAMESPACE__ . '\\divi4_get_terms_sort', 20, 4);
    return $props;
}

// Remove the filter and clean up the global after module output
add_filter('et_module_shortcode_output', function($output, $render_slug, $module) {
    if ($render_slug !== DIVI4_MODULE_SLUG) {
        return $output;
    }
    // Remove the get_terms filter to avoid conflicts
    remove_filter('get_terms', __NAMESPACE__ . '\\divi4_get_terms_sort', 20);
    // Clean up the global variable
    unset($GLOBALS['divibooster_divi4_tab_order_atts']);
    return $output;
}, 10, 3);

// === Divi 5 Output Filter: Adjust Terms during block render ===
add_filter('render_block_' . DIVI5_MODULE_SLUG, __NAMESPACE__.'\\divi5_filterable_portfolio_tab_order', 11, 3);
function divi5_filterable_portfolio_tab_order($block_content, $parsed_block, $block) {
    // Defensive attempt to emulate terms filter for D5
    $attrs = $parsed_block['attrs'] ?? [];
    $order_type = $attrs[DIVI5_TAB_ORDER_SLUG]['desktop']['value'] ?? ($attrs[DIVI5_TAB_ORDER_SLUG]['value'] ?? 'default');
    $order_slugs = $attrs[DIVI5_TAB_ORDER_SLUGS]['desktop']['value'] ?? ($attrs[DIVI5_TAB_ORDER_SLUGS]['value'] ?? '');

    if ($order_type === 'default') return $block_content;
    // Only try to resort tabs if order is non-default
    $block_content = divibooster_sort_filterable_portfolio_tabs_html($block_content, $order_type, $order_slugs);
    return $block_content;
}

// === Shared: Resort Tabs in Portfolio Module HTML (for D5) ===
function divibooster_sort_filterable_portfolio_tabs_html($html, $order_type, $order_slugs) {
    $pattern = '/(<div class="[^"]*et_pb_portfolio_filters[^"]*"><ul[^>]*>)(.*?)(<\/ul><\/div>)/s';
    if (preg_match($pattern, $html, $matches) && isset($matches[2])) {
        // Find all the <li>...</li>
        preg_match_all('/<li[^>]*>.*?<\/li>/s', $matches[2], $li_matches);
        $lis = $li_matches[0] ?? [];

        $all_li = null;
        $term_lis = [];

        // Separate 'all' filter and term filters
        foreach ($lis as $li) {
            if (strpos($li, 'et_pb_portfolio_filter_all') !== false) {
                $all_li = $li;
            } elseif (preg_match('/data-category-slug=["\']([^"\']+)["\']/', $li, $m)) {
                $term_lis[$m[1]] = $li;
            } else {
                $term_lis[] = $li; // fallback
            }
        }

        // Sort term filters
        if ($order_type === 'by_slug') {
            $slug_list = array_map('trim', explode(',', $order_slugs));
            $ordered = [];
            foreach ($slug_list as $slug) {
                if (isset($term_lis[$slug])) {
                    $ordered[] = $term_lis[$slug];
                    unset($term_lis[$slug]);
                }
            }
            // Remaining terms, preserve order
            foreach ($term_lis as $li) $ordered[] = $li;
            $term_lis = $ordered;
        } elseif ($order_type === 'reverse') {
            $term_lis = array_reverse(array_values($term_lis));
        } elseif ($order_type === 'random') {
            $tmp = array_values($term_lis);
            shuffle($tmp);
            $term_lis = $tmp;
        } else {
            $term_lis = array_values($term_lis);
        }

        // Rebuild li list: always put 'all' filter first (if present)
        $new_lis = [];
        if ($all_li !== null) {
            $new_lis[] = $all_li;
        }
        foreach ($term_lis as $li) {
            $new_lis[] = $li;
        }

        $new_inner = implode("", $new_lis);
        $html = preg_replace($pattern, "$1{$new_inner}$3", $html);
    }
    return $html;
}

