<?php

namespace UiCoreBlocks;

use WP_HTML_Tag_Processor;

class WooFrontend
{
    /**
     * Attributes to remove from Woo blocks
     */
    const CLEANUP_ATTR_LIST = [
        "fontDsPr",
        "fontSizeDsPr",
        "letterSpacingDsPr",
        "lineHeightDsPr",
        "colorDsPr",
        "alignSelf",
        "columnSpan",
        "rowSpan",
        "flexAlignSelf",
        "order",
        "display",
        "gOutline",
        "gFlow",
        "gColumns",
        "gRows",
        "direction",
        "align",
        "justify",
        "wrap",
        "gap",
        "m",
        "p",
        "width",
        "height",
        "minWidth",
        "minHeight",
        "maxWidth",
        "maxHeight",
        "overflow",
        "bg",
        "font",
        "fontSize",
        "letterSpacing",
        "lineHeight",
        "color",
        //"textAlign",
        "textTransform",
        "wordBreak",
        "lineBreak",
        "textWrap",
        "linkColor",
        "borderStyle",
        "border",
        "borderColor",
        "borderColorGlow",
        "borderColorGradient",
        "borderRadius",
        "shadow",
        "position",
        "vertical",
        "vOffset",
        "horizontal",
        "hOffset",
        "zIndex",
        "opacity",
        "filter",
        "bgFilter",
        "transform",
        "transition",
        "blendingMode",
        "cursor",
        "customCursor",
        "animationTrigger",
        "animationName",
        "animationDuration",
        "animationDelay",
        "animationOffset",
        "imageMaskBlock",
        "maskSize",
        "repeat",
        "maskLeftPosition",
        "maskTopPosition",
        "maskWidth",
        "maskHeight",
        "customCss",
        "tag",
        //"url",
        //"target",
        "visibility",
        //"id", 
        //"tagAttrs",
        "syncParent",
        "desyncKeys",
        "___",
        //"blockId",
        "advanced",
        "isActive",
        "classNames",
        "icon",
        "iconColor",
        "iconSize",
        "navOffsetX",
        "navOffsetY",
        "fontSizeStar",
        "starSpacing",
        "colorStar",
        "qFontSize",
        "qColor",
        "qBorder",
        "qBorderStyle",
        "qBorderColor",
        "qBorderRadius",
        "layout",
    ];

    /**
     * Attributes to remove from Woo blocks if they are JSON/Objects
     */
    const CLEANUP_ATTR_LIST_OBJECTS = ['textAlign'];

    /**
     * On some blocks we don't need to process attributes.
     */
    const BLOCKS_WITHOUT_ATTR_PROCESSING = [
        'woocommerce/product-gallery-large-image-next-previous',
        'woocommerce/product-gallery-large-image',
        'woocommerce/product-price',
    ];

    /**  
     * Some blocks have inner blocks that we want to process their inner blocks attributes as well.
     */
    const BLOCKS_WITH_INNER_BLOCKS_ATTR_PROCESSING = ['woocommerce/product-gallery-large-image'];

    public function __construct()
    {
        add_filter('render_block_data', [$this, 'update_uicore_woo_block_attributes'], 10, 1);
        add_filter('render_block', [$this, 'update_uicore_woo_block_data_attributes'], 99, 2);
    }

    /**
     * Remove woo block attributes before rendering the block
     * The scope of this function is to add uicore classes on woo blocks and remove block attributes because 
     * woocommerce add them as data-attributes using using __experimental_woocommerce_blocks_add_data_attributes_to_block filter
     *
     * @param array $block
     * @param bool $process_inner
     * @return array
     */

    public function update_uicore_woo_block_attributes(
        array $block,
        bool $process_inner = true
    ): array {
        if (is_admin()) {
            return $block;
        }

        if (!isset($block['attrs']) || !is_array($block['attrs'])) {
            return $block;
        }

        $attrs        = $block['attrs'];
        $wc_namespace = $attrs['__woocommerceNamespace'] ?? null;

        $is_woo_by_name      = !empty($block['blockName']) && strpos($block['blockName'], 'woocommerce/') === 0;
        $is_woo_by_namespace = !empty($wc_namespace);
        $block_id            = $attrs['blockId'] ?? null;

        $is_woo = ($is_woo_by_name || $is_woo_by_namespace) && !empty($block_id);

        if ($is_woo) {

            if (!in_array($block['blockName'], self::BLOCKS_WITHOUT_ATTR_PROCESSING, true)) {
                $block['attrs']['className'] = implode(
                    ' ',
                    array_unique(
                        preg_split(
                            '/\s+/',
                            trim(
                                ($block['attrs']['className'] ?? '') .
                                    ' uicore-bl-content uicore-bl-woocommerce uicore-block-' . $block_id . ' ' .
                                    ($block['attrs']['classNames'] ?? '')
                            )
                        )
                    )
                );

                unset($block['attrs']['blockId']);
            }

            // Attribute cleanup
            foreach (self::CLEANUP_ATTR_LIST as $attr) {
                if (isset($block['attrs'][$attr])) {
                    unset($block['attrs'][$attr]);
                }
            }

            // Attribute cleanup for objects
            foreach (self::CLEANUP_ATTR_LIST_OBJECTS as $attr) {
                if (isset($block['attrs'][$attr]) && !is_object($block['attrs'][$attr])) {
                    unset($block['attrs'][$attr]);
                }
            }
        }

        // Process inner blocks
        if (
            $process_inner &&
            in_array($block['blockName'], self::BLOCKS_WITH_INNER_BLOCKS_ATTR_PROCESSING, true) &&
            !empty($block['innerBlocks']) &&
            is_array($block['innerBlocks'])
        ) {
            foreach ($block['innerBlocks'] as $i => $inner) {
                if (!is_array($inner)) {
                    continue;
                }

                // Reuse SAME function, but disable further inner processing
                $block['innerBlocks'][$i] =
                    $this->update_uicore_woo_block_attributes($inner, false);
            }
        }

        return $block;
    }


    /** 
     * Update Woo blocks that haves tagAttrs or id attribute to add them as real HTML attributes
     * Woocommerce add all gutenberg blocks as data-attributes, and because tagAttrs is an array of objects, 
     * we need to convert them to real attributes
     *
     * @param string $block_content
     * @param array $block
     * @return string
     */
    public function update_uicore_woo_block_data_attributes($block_content, $block)
    {
        if (is_admin() || empty($block_content) || !is_array($block)) {
            return $block_content;
        }

        $attrs        = isset($block['attrs']) && is_array($block['attrs']) ? $block['attrs'] : [];
        $wc_namespace = isset($attrs['__woocommerceNamespace']) ? $attrs['__woocommerceNamespace'] : null;

        $is_woo_by_name      = !empty($block['blockName']) && strpos($block['blockName'], 'woocommerce/') === 0;
        $is_woo_by_namespace = !empty($wc_namespace);
        $tagAttrs            = isset($attrs['tagAttrs']) && is_array($attrs['tagAttrs']) ? $attrs['tagAttrs'] : [];
        $hasTagAttrs         = !empty($tagAttrs);
        $hasId               = !empty($attrs['id']);
        $hasBlockId          = !empty($attrs['blockId']);

        if (($is_woo_by_name || $is_woo_by_namespace) && ($hasTagAttrs || $hasId || $hasBlockId)) {
            $html = $block_content;

            if (class_exists('\WP_HTML_Tag_Processor')) {
                $p = new \WP_HTML_Tag_Processor($html);

                if ($p->next_tag()) {

                    if ($hasTagAttrs) {
                        foreach ($tagAttrs as $item) {
                            if (!is_array($item) || empty($item['name'])) {
                                continue;
                            }

                            $name  = (string) $item['name'];
                            $value = isset($item['value']) ? (string) $item['value'] : '';

                            $p->set_attribute($name, $value);
                        }

                        // Remove the config attribute itself
                        $p->remove_attribute('data-tag-attrs');
                    }

                    if ($hasId) {
                        $p->set_attribute('id', $attrs['id']);
                        $p->remove_attribute('data-id');
                    }

                    if ($hasBlockId) {
                        $block_id = (string) $attrs['blockId'];
                        $existing_class = (string) $p->get_attribute('class');
                        $append = 'uicore-bl-content uicore-bl-woocommerce uicore-block-' . $block_id;

                        // Merge + de-duplicate
                        $classes = preg_split('/\s+/', trim($existing_class . ' ' . $append));
                        $classes = array_values(array_unique(array_filter($classes)));

                        if (!empty($classes)) {
                            $p->set_attribute('class', implode(' ', $classes));
                        }

                        $p->remove_attribute('data-block-id');
                    }

                    $html = $p->get_updated_html();
                }
            }

            return $html;
        }

        return $block_content;
    }
}
