<?php

if (!defined('ABSPATH')) {
    exit;
}

class AIEO_Blocks_Loader {

    private static $registered = false;

    public static function bootstrap() {
        if (self::$registered) { return; }
        self::$registered = true;
        add_action('init', array(__CLASS__, 'register_blocks'), 30);
        add_filter('render_block_data', array(__CLASS__, 'inject_product_card_swatches'), 10, 2);

        
        
        
        
        add_filter('allowed_block_types_all', array(__CLASS__, 'keep_aieo_blocks_allowed'), 11, 2);

        
        
        
        
        
        
        add_action('enqueue_block_editor_assets', array(__CLASS__, 'enqueue_generic_block_fallback'));

        
        
        
        
        
        
        
        
        
        
        
        
        
        add_action('init', array(__CLASS__, 'kill_om_ppe_variations_gallery'), 999);
        add_filter('script_loader_src', array(__CLASS__, 'block_om_ppe_script_url'), 10, 2);
        add_action('wp_enqueue_scripts', array(__CLASS__, 'dequeue_om_ppe_variations_gallery'), 999);

        
        
        
        if ( ! defined( 'AIEO_RUNTIME_OWNS_AJAX' ) ) {
            add_action('wc_ajax_aieo_fs_pdp_state',         array(__CLASS__, 'fs_pdp_state'));
            add_action('wp_ajax_aieo_fs_pdp_state',         array(__CLASS__, 'fs_pdp_state'));
            add_action('wp_ajax_nopriv_aieo_fs_pdp_state',  array(__CLASS__, 'fs_pdp_state'));
        }

        
        
        
        
        
        
        add_action('wp_enqueue_scripts', array(__CLASS__, 'suppress_legacy_pdp_assets'), 1000);
    }

    
    public static function kill_om_ppe_variations_gallery() {
        
        
        
        
        
        
        
        
        
        if (class_exists('OM_Product_Page_Essentials')) {
            $plugin = OM_Product_Page_Essentials::instance();
            if (isset($plugin->modules['variations-gallery'])) {
                self::detach_legacy_gallery_module($plugin->modules['variations-gallery']);
            }
        }
    }

    
    private static function detach_legacy_gallery_module($module) {
        if (!is_object($module)) { return; }
        if (method_exists($module, 'register_scripts')) {
            remove_action('wp_enqueue_scripts', array($module, 'register_scripts'));
        }
        if (method_exists($module, 'add_variation_gallery_data')) {
            remove_filter('woocommerce_available_variation', array($module, 'add_variation_gallery_data'), 10);
        }
        if (method_exists($module, 'maybe_enqueue_scripts')) {
            remove_action('woocommerce_before_shop_loop_item', array($module, 'maybe_enqueue_scripts'));
        }
    }

    
    public static function dequeue_om_ppe_variations_gallery() {
        if (function_exists('wp_dequeue_script'))    { wp_dequeue_script('om-ppe-variations-gallery'); }
        if (function_exists('wp_deregister_script')) { wp_deregister_script('om-ppe-variations-gallery'); }
    }

    
    public static function block_om_ppe_script_url($src, $handle) {
        if ($handle === 'om-ppe-variations-gallery') {
            return false;
        }
        return $src;
    }

    
    public static function fs_pdp_state() {
        if (!class_exists('AIEO_DMM_Free_Shipping') || !function_exists('WC') || !WC()->cart) {
            wp_send_json_error(array('reason' => 'unavailable'));
        }
        $module = new AIEO_DMM_Free_Shipping();
        $s = $module->get_settings();
        $threshold = (float) ($s['free_shipping_threshold'] ?? 0);
        if ($threshold <= 0) {
            wp_send_json_success(array(
                'message_html' => '',
                'fill_percent' => 0,
                'qualified'    => false,
            ));
        }
        $include_tax = ($s['include_tax'] ?? 'no') === 'yes';
        $cart_total  = $include_tax
            ? (float) WC()->cart->get_subtotal() + (float) WC()->cart->get_subtotal_tax()
            : (float) WC()->cart->get_subtotal();
        $remaining = max(0.0, $threshold - $cart_total);
        $qualified = $remaining <= 0;
        $percent   = $qualified ? 100 : (int) max(0, min(100, ($cart_total / $threshold) * 100));

        $tpl = $qualified
            ? (string) ($s['msg_success']  ?? '')
            : ($cart_total <= 0
                ? (string) ($s['msg_initial']  ?? '')
                : (string) ($s['msg_progress'] ?? ''));
        $msg = strtr($tpl, array(
            '{amount}'    => function_exists('wc_price') ? wc_price($threshold) : (string) $threshold,
            '{remaining}' => function_exists('wc_price') ? wc_price($remaining) : (string) $remaining,
        ));
        wp_send_json_success(array(
            'message_html' => $msg,
            'fill_percent' => $percent,
            'qualified'    => $qualified,
        ));
    }

    
    public static function suppress_legacy_pdp_assets() {
        if (!function_exists('is_singular') || !is_singular('product')) { return; }
        if (!(bool) get_option('aieo_block_pdp_active', true))            { return; }
        if (!function_exists('wp_dequeue_script') || !function_exists('wp_dequeue_style')) { return; }

        
        
        
        
        
        
        
        
        
        
        
        $handles = array(
            'om-ppe-frontend',
            'om-ppe-product-brand',
            'om-ppe-product-meta',
            'om-ppe-product-needs',
            'om-ppe-trust-badges',
            'om-ppe-payment-logos',
            'om-ppe-wait-list',
            'om-ppe-recently-viewed',
            'om-ppe-product-video',
            'om-ppe-sale-eligibility',
        );
        foreach ($handles as $h) {
            wp_dequeue_script($h);
            wp_dequeue_style($h);
        }
    }

    
    public static function keep_aieo_blocks_allowed($allowed, $context = null) {
        if (!is_array($allowed) || !class_exists('WP_Block_Type_Registry')) {
            return $allowed;
        }
        foreach (array_keys(WP_Block_Type_Registry::get_instance()->get_all_registered()) as $name) {
            if (0 === strpos((string) $name, 'aieo/') && !in_array($name, $allowed, true)) {
                $allowed[] = $name;
            }
        }
        return array_values($allowed);
    }

    
    public static function aieo_title($title) {
        $title = (string) $title;
        return (0 === stripos($title, 'AIEO')) ? $title : 'AIEO ' . $title;
    }

    
    public static function get_block_manifest_for_editor() {
        $base = AIEO_DIR . 'includes/dmm/blocks/';
        if (!is_dir($base)) { return array(); }

        $out = array();
        foreach (scandir($base) as $entry) {
            if ($entry === '' || $entry[0] === '.') { continue; }
            $dir = $base . $entry;
            if (!is_dir($dir)) { continue; }
            $json_path = $dir . '/block.json';
            if (!is_file($json_path)) { continue; }
            $json = json_decode((string) file_get_contents($json_path), true);
            if (!is_array($json) || empty($json['name'])) { continue; }

            $out[] = array(
                'name'       => (string) $json['name'],
                'title'      => self::aieo_title(isset($json['title']) ? (string) $json['title'] : (string) $json['name']),
                'category'   => isset($json['category']) ? (string) $json['category'] : 'theme',
                'icon'       => isset($json['icon']) ? (string) $json['icon'] : 'block-default',
                'attributes' => isset($json['attributes']) && is_array($json['attributes']) ? $json['attributes'] : array(),
                'hasOwnEdit' => is_file($dir . '/edit.js'),
            );
        }

        
        
        
        
        
        
        
        
        if (class_exists('WP_Block_Type_Registry')) {
            $seen = array();
            foreach ($out as $m) { $seen[$m['name']] = true; }
            foreach (WP_Block_Type_Registry::get_instance()->get_all_registered() as $bname => $bt) {
                if (0 !== strpos($bname, 'aieo/') || isset($seen[$bname])) { continue; }
                $icon = 'block-default';
                if (is_string($bt->icon) && '' !== $bt->icon) {
                    $icon = $bt->icon;
                } elseif (is_array($bt->icon) && ! empty($bt->icon['src']) && is_string($bt->icon['src'])) {
                    $icon = $bt->icon['src'];
                }
                $out[] = array(
                    'name'       => $bname,
                    'title'      => self::aieo_title((string) ('' !== (string) $bt->title ? $bt->title : $bname)),
                    'category'   => (is_string($bt->category) && '' !== $bt->category) ? $bt->category : 'widgets',
                    'icon'       => $icon,
                    'attributes' => is_array($bt->attributes) ? $bt->attributes : array(),
                    'hasOwnEdit' => false,
                );
            }
        }
        return $out;
    }

    
    public static function enqueue_generic_block_fallback() {
        if (!function_exists('wp_register_script')) { return; }

        $manifest = self::get_block_manifest_for_editor();
        if (empty($manifest)) { return; }

        wp_register_script(
            'aieo-block-editor-fallback',
            '', 
            array('wp-blocks', 'wp-element', 'wp-block-editor', 'wp-components', 'wp-i18n', 'wp-server-side-render'),
            defined('AIEO_VERSION') ? AIEO_VERSION : '1.0',
            true
        );
        wp_enqueue_script('aieo-block-editor-fallback');

        $localised = 'window.aieoBlockEditorFallback = ' . wp_json_encode(array(
            'blocks' => $manifest,
        )) . ';';
        wp_add_inline_script('aieo-block-editor-fallback', $localised, 'before');

        $js = <<<'JS'
(function(wp){
    if (!wp || !wp.blocks || !wp.element) { return; }
    var data = window.aieoBlockEditorFallback || { blocks: [] };

    var el                = wp.element.createElement;
    var Fragment          = wp.element.Fragment;
    var registerBlockType = wp.blocks.registerBlockType;
    var getBlockType      = wp.blocks.getBlockType;
    var ServerSideRender  = wp.serverSideRender || (wp.editor && wp.editor.ServerSideRender);
    var InspectorControls = wp.blockEditor && wp.blockEditor.InspectorControls;
    var useBlockProps     = wp.blockEditor && wp.blockEditor.useBlockProps;
    var PanelBody         = wp.components && wp.components.PanelBody;
    var ToggleControl     = wp.components && wp.components.ToggleControl;
    var TextControl       = wp.components && wp.components.TextControl;
    var NumberControl     = wp.components && (wp.components.__experimentalNumberControl || wp.components.NumberControl);
    var SelectControl     = wp.components && wp.components.SelectControl;
    var __                = (wp.i18n && wp.i18n.__) || function (s) { return s; };

    function inspectorFor(name, attrSpec, attrs, setAttr) {
        if (!InspectorControls || !PanelBody) { return null; }
        var rows = [];
        Object.keys(attrSpec || {}).forEach(function (key) {
            var spec = attrSpec[key] || {};
            var t    = spec.type;
            var lbl  = key;
            // Render enum-style strings as SelectControl, booleans as
            // ToggleControl, numbers as NumberControl (or plain text fallback),
            // plain strings as TextControl. Anything else is skipped — the
            // block's own edit.js (if it ships one) takes over instead.
            if (t === 'boolean' && ToggleControl) {
                rows.push(el(ToggleControl, {
                    key: key,
                    label: lbl,
                    checked: !!attrs[key],
                    onChange: setAttr(key),
                }));
            } else if (Array.isArray(spec.enum) && SelectControl) {
                rows.push(el(SelectControl, {
                    key: key,
                    label: lbl,
                    value: attrs[key] != null ? attrs[key] : (spec['default'] || ''),
                    options: spec.enum.map(function (v) { return { label: String(v), value: v }; }),
                    onChange: setAttr(key),
                }));
            } else if (t === 'number' && NumberControl) {
                rows.push(el(NumberControl, {
                    key: key,
                    label: lbl,
                    value: attrs[key] != null ? attrs[key] : (spec['default'] != null ? spec['default'] : 0),
                    onChange: function (v) { setAttr(key)(parseInt(v, 10) || 0); },
                }));
            } else if (t === 'string' && TextControl) {
                rows.push(el(TextControl, {
                    key: key,
                    label: lbl,
                    value: attrs[key] != null ? attrs[key] : (spec['default'] || ''),
                    onChange: setAttr(key),
                }));
            }
        });
        if (!rows.length) { return null; }
        return el(InspectorControls, {},
            el(PanelBody, { title: __('Settings', 'ai-eshop-optimizer'), initialOpen: true }, rows)
        );
    }

    (data.blocks || []).forEach(function (b) {
        if (!b || !b.name) { return; }
        // If the block already has its own edit.js the loader emits
        // editorScript on init and registerBlockType is called there
        // — don't double-register.
        if (b.hasOwnEdit) { return; }
        // Defensive: getBlockType returns truthy if registered already.
        if (getBlockType && getBlockType(b.name)) { return; }

        registerBlockType(b.name, {
            title:       b.title || b.name,
            category:    b.category || 'theme',
            icon:        b.icon || 'block-default',
            description: b.title ? (b.title + ' — server-rendered AIEO block.') : '',
            attributes:  b.attributes || {},
            supports:    { html: false },
            edit: function (props) {
                var attrs = props.attributes || {};
                var setAttr = function (k) {
                    return function (v) { var p = {}; p[k] = v; props.setAttributes(p); };
                };
                var bp = useBlockProps ? useBlockProps() : {};
                var inspector = inspectorFor(b.name, b.attributes, attrs, setAttr);
                return el(Fragment, {},
                    inspector,
                    el('div', bp,
                        ServerSideRender
                            ? el(ServerSideRender, { block: b.name, attributes: attrs })
                            : el('div', { style: { padding: '12px', background: '#f6f7f7', color: '#646970' } },
                                (b.title || b.name) + ' — preview only on the front-end.')
                    )
                );
            },
            save: function () { return null; },
        });
    });
})(window.wp);
JS;

        wp_add_inline_script('aieo-block-editor-fallback', $js);
    }

    public static function register_blocks() {
        if (!function_exists('register_block_type')) { return; }

        
        
        
        
        
        self::register_shared_styles();

        $base = AIEO_DIR . 'includes/dmm/blocks/';
        if (!is_dir($base)) { return; }

        $registry = class_exists('WP_Block_Type_Registry')
            ? WP_Block_Type_Registry::get_instance()
            : null;

        foreach (scandir($base) as $entry) {
            if ($entry === '' || $entry[0] === '.') { continue; }
            $block_dir = $base . $entry;
            
            
            if (!is_dir($block_dir)) { continue; }
            $block_json = $block_dir . '/block.json';
            if (!is_file($block_json)) { continue; }
            
            
            
            
            
            
            
            if ($registry) {
                $block_name = self::peek_block_name($block_json);
                if ($block_name !== '' && $registry->is_registered($block_name)) { continue; }
            }
            register_block_type($block_json);
        }

        
        
        
        
        
        
        self::merge_shared_block_attributes();
    }

    
    public static function merge_shared_block_attributes() {
        if (!class_exists('WP_Block_Type_Registry')) { return; }
        $extra = array();
        if (class_exists('AIEO_Block_Header') && method_exists('AIEO_Block_Header', 'block_attributes')) {
            $extra += AIEO_Block_Header::block_attributes();
        }
        if (class_exists('AIEO_Responsive_Controls') && method_exists('AIEO_Responsive_Controls', 'block_attributes')) {
            $extra += AIEO_Responsive_Controls::block_attributes();
        }
        if (empty($extra)) { return; }

        $registry = WP_Block_Type_Registry::get_instance();
        foreach ($registry->get_all_registered() as $block_name => $block_type) {
            if (strpos((string) $block_name, 'aieo/') !== 0) { continue; }
            $attrs = is_array($block_type->attributes) ? $block_type->attributes : array();
            foreach ($extra as $k => $schema) {
                if (!isset($attrs[$k])) { $attrs[$k] = $schema; }
            }
            $block_type->attributes = $attrs;
        }
    }

    
    private static function peek_block_name($block_json_path) {
        $raw = @file_get_contents($block_json_path);
        if ($raw === false || $raw === '') { return ''; }
        $decoded = json_decode($raw, true);
        if (!is_array($decoded) || empty($decoded['name'])) { return ''; }
        return (string) $decoded['name'];
    }

    
    private static function register_shared_styles() {
        if (!function_exists('wp_register_style')) { return; }
        if (!defined('AIEO_DIR')) { return; }

        $rel_path = 'assets/css/aieo-article-cards.css';
        $abs_file = AIEO_DIR . $rel_path;
        
        
        
        $url      = plugins_url($rel_path, AIEO_DIR . 'ai-eshop-optimizer.php');
        $version  = file_exists($abs_file) ? (string) filemtime($abs_file) : '1.0';

        wp_register_style('aieo-article-cards', $url, array(), $version);

        
        
        
        
        if (!wp_style_is('aieo-recommendations', 'registered')) {
            $reco_rel = 'assets/css/aieo-recommendations.css';
            $reco_abs = AIEO_DIR . $reco_rel;
            wp_register_style(
                'aieo-recommendations',
                plugins_url($reco_rel, AIEO_DIR . 'ai-eshop-optimizer.php'),
                array(),
                file_exists($reco_abs) ? (string) filemtime($reco_abs) : '1.0'
            );
        }
    }

    
    public static function inject_product_card_swatches($parsed_block, $source_block) {
        if (!is_array($parsed_block) || empty($parsed_block['blockName'])) {
            return $parsed_block;
        }
        if ($parsed_block['blockName'] !== 'woocommerce/product-template') {
            return $parsed_block;
        }
        if (!apply_filters('aieo_product_card_swatches_auto_inject', true, $parsed_block, $source_block)) {
            return $parsed_block;
        }

        $inner = isset($parsed_block['innerBlocks']) && is_array($parsed_block['innerBlocks'])
            ? $parsed_block['innerBlocks']
            : array();

        foreach ($inner as $child) {
            if (is_array($child) && isset($child['blockName']) && $child['blockName'] === 'aieo/product-card-swatches') {
                return $parsed_block;
            }
        }

        
        
        
        
        
        
        
        
        $inner[] = array(
            'blockName'    => 'aieo/product-card-swatches',
            'attrs'        => array(),
            'innerBlocks'  => array(),
            'innerHTML'    => '',
            'innerContent' => array(),
        );
        $parsed_block['innerBlocks'] = $inner;

        
        
        
        
        
        
        $inner_content = isset($parsed_block['innerContent']) && is_array($parsed_block['innerContent'])
            ? $parsed_block['innerContent']
            : array();
        $inner_content[] = null;
        $parsed_block['innerContent'] = $inner_content;

        return $parsed_block;
    }
}
