<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

/**
 * Generic Text Replacer for Gutenberg Blocks (Kadence-safe)
 * --------------------------------------------------------
 * - Traverse block AST
 * - Replace FIRST valid text node with {fillable}
 * - UTF-8 safe
 * - Core blocks: innerHTML only
 * - Kadence Advanced Heading: innerHTML + innerContent + attrs.content
 * - Safe for serialize_blocks()
 */

class PufferGo_Generic_Text_Replacer {

    private static $ALLOWED_TAGS = [
        'h1','h2','h3','h4','h5','h6',
        'p','span','li',
        'strong','b','em','i'
    ];

    public static function process_blocks(array $blocks): array {
        return self::walk_blocks($blocks);
    }

    private static function walk_blocks(array $blocks): array {
        foreach ($blocks as &$block) {

            if (
                isset($block['innerHTML']) &&
                is_string($block['innerHTML']) &&
                trim($block['innerHTML']) !== ''
            ) {
                $block = self::replace_inner_html($block);
            }

            if (!empty($block['innerBlocks']) && is_array($block['innerBlocks'])) {
                $block['innerBlocks'] = self::walk_blocks($block['innerBlocks']);
            }
        }

        return $blocks;
    }

    private static function replace_inner_html(array $block): array {
        $html = $block['innerHTML'];

        $wrappedHtml = '<?xml encoding="utf-8" ?>' . $html;

        $prev = libxml_use_internal_errors(true);
        $dom  = new DOMDocument('1.0', 'UTF-8');

        if (!$dom->loadHTML(
            $wrappedHtml,
            LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
        )) {
            libxml_clear_errors();
            libxml_use_internal_errors($prev);
            return $block;
        }

        libxml_clear_errors();
        libxml_use_internal_errors($prev);

        $xpath = new DOMXPath($dom);

        $query = implode('|', array_map(
            fn($t) => "//{$t}//text()[normalize-space()]",
            self::$ALLOWED_TAGS
        ));

        $nodes = $xpath->query($query);

        if (!$nodes || $nodes->length === 0) {
            return $block;
        }

        foreach ($nodes as $node) {
            if (trim($node->nodeValue) === '{fillable}') {
                continue;
            }

            $node->nodeValue = '{fillable}';
            break;
        }

        $newHtml = str_replace(
            '<?xml encoding="utf-8" ?>',
            '',
            $dom->saveHTML()
        );

        // ✅ Always update innerHTML
        $block['innerHTML'] = $newHtml;

        /**
         * ⭐ Kadence Advanced Heading FIX
         * serialize_blocks() READS innerContent
         */
        if ($block['blockName'] === 'kadence/advancedheading') {

            // Sync innerContent (SOURCE OF TRUTH)
            $block['innerContent'][0] = $newHtml;

            // Optional consistency (not required but clean)
            $block['attrs']['content'] = '{fillable}';
        }

        return $block;
    }
}
