<?php

namespace UiCoreBlocks;

use WP_REST_Request;

/**
 * BlocksSave Class
 */
class BlocksSave
{

    function __construct()
    {
        add_action('save_post', [$this, 'extract_assets_from_post_content']);
        add_action('save_post', [$this, 'add_data_form_page_in_forms']);
        add_action('rest_after_save_widget', [$this, 'extract_assets_from_widgets_content'], 10, 2);
        add_action('rest_delete_widget', [$this, 'extract_assets_from_widgets_content'], 10, 2);
    }

    /**
     * Injects data-form-page="{post_id}" into every <form> tag in given content.
     *
     * @param string $content The post content to scan.
     * @param int    $post_id The ID of the current post.
     * @return void
     */
    public function add_data_form_page_in_forms(int $post_id): void
    {
        $post = get_post($post_id);

        if (!$post) {
            return;
        }

        if (!empty($post->post_content) && stripos($post->post_content, 'data-form-page') !== false) {
            remove_action('save_post', [$this, 'add_data_form_page_in_forms']);

            $content = $post->post_content;
            $formPage = $post_id;

            $p = addslashes((string)$formPage);

            $content = preg_replace(
                '/(?:\s*data-form-page\s*=\s*(?:"[^"]*"|\'[^\']*\'|[^\s>]+))/i',
                '',
                $content
            );

            $content = preg_replace(
                '/<form\b([^>]*)>/i',
                '<form$1 data-form-page="' . $p . '">',
                $content
            );

            $post->post_content = $content;
            wp_update_post($post);

            // Re-hook the save_post action
            add_action('save_post', [$this, 'add_data_form_page_in_forms'], 10, 1);
        }
    }

    /**
     * Extracts CSS and assets from post content and saves it to post meta.
     *
     * @param int $post_id The ID of the post being saved.
     * @return void
     */
    public static function extract_assets_from_post_content(int $post_id): void
    {
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }

        //prevent duble runs
        static $ran = false;
        if ($ran) {
            return;
        }
        $ran = true;

        $post = get_post($post_id);

        if (!$post) {
            return;
        }


        $required_assets = self::get_blocks_content_required_assets($post->post_content);

        $initial_required_assets = get_post_meta($post_id, '_uicore_block_assets', true);

        if (!is_array($initial_required_assets)) {
            $initial_required_assets = [];
        }

        $required_assets = array_merge($initial_required_assets, $required_assets);
        if (self::recursive_is_empty($required_assets)) {
            \delete_post_meta($post_id, '_uicore_block_assets');
            return;
        }
        update_post_meta($post_id, '_uicore_block_assets', $required_assets);
    }

    /**
     * Callback fired after a widget is saved/deleted via the REST API.
     *
     * @param string $widget_id  The widget instance ID (e.g. "block-3").
     * @param string $sidebar_id The sidebar identifier (e.g. "footer-1").
     * @return void
     */

    public function extract_assets_from_widgets_content(string $widget_id, string $sidebar_id): void
    {
        if ($sidebar_id === 'wp_inactive_widgets') {
            return;
        }

        $sidebars = wp_get_sidebars_widgets();

        if (empty($sidebars)) {
            return;
        }
        $widgets_ids = $sidebars[$sidebar_id] ?? [];

        if (empty($widgets_ids)) {
            delete_option("_uicore_widget_block_assets_{$sidebar_id}");
            return;
        }

        $styles_list = [];
        $scripts_list = [];

        foreach ($widgets_ids as $wid) {
            list($base, $num) = explode('-', $wid, 2);
            $instances = get_option("widget_{$base}", []);
            $instance  = $instances[$num] ?? [];

            // get the raw HTML/text field
            $content = $instance['content']
                ?? $instance['text']
                ?? '';

            // parse this widget
            $assets = self::get_blocks_content_required_assets($content);

            $styles_list = array_values(array_unique(array_merge($styles_list, $assets['styles'])));
            $scripts_list = array_values(array_unique(array_merge($scripts_list, $assets['scripts'])));
        }

        if (empty($styles_list) && empty($scripts_list)) {
            delete_option("_uicore_widget_block_assets_{$sidebar_id}");
            return;
        }

        $required_assets = [
            'styles'  => $styles_list,
            'scripts' => $scripts_list,
        ];

        update_option("_uicore_widget_block_assets_{$sidebar_id}", $required_assets);
    }

    /**
     * Examine a chunk of content and return the required asset handles.
     *
     * @param  string $content  Arbitrary HTML/text to scan.
     * @return array{
     *   styles:   string[],
     *   scripts:  string[],
     * }
     */
    public static function get_blocks_content_required_assets(string $content): array
    {
        $required_styles = [];
        $styles_snippets = Assets::get_snippets_styles();
        foreach ($styles_snippets as $handle => $css) {
            if (strpos($content, $handle) !== false) {
                $required_styles[] = $handle;
            }
        }

        $required_js = [];
        $js_snippets  = Assets::get_snippets_scripts();
        foreach ($js_snippets as $handle => $js) {
            if (strpos($content, $handle) !== false) {
                $required_js[] = $handle;
            }
        }

        // also catch any "uicore-bl-block wp-block-uicore-{name}"
        if (preg_match_all(
            '/uicore-bl-block\s+wp-block-uicore-([^\s"]+)/',
            $content,
            $matches
        )) {
            foreach (array_unique($matches[1]) as $block) {
                $required_styles[] = 'uicore-' . $block . '-style';
            }
        }

        return [
            'styles'  => array_values(array_unique($required_styles)),
            'scripts' => array_values(array_unique($required_js)),
        ];
    }

    /**
     * Save styles & fonts for either a post (numeric ID) or a sidebar (string key).
     *
     * @param int|string $targetId  Post ID or sidebar key.
     * @param ?string      $styles    The styles array from the REST request.
     * @param ?array      $fonts     The fonts array from the REST request.
     * @return void
     */
    public static function save_styles_for_post_or_widget($targetId, ?array $styles, ?array $fonts, ?array $preloadImages): void
    {
        // -------------------------
        // Encode fonts
        // -------------------------
        $fonts_save = '';

        if (!empty($fonts)) {
            $encoded = wp_json_encode($fonts);

            if (is_string($encoded)) {
                $fonts_save = $encoded;
            }
        }

        // -------------------------
        // POSTS
        // -------------------------
        if (is_numeric($targetId)) {

            $styles = empty($styles) ? [] : $styles;
            $styles_save = str_replace('.editor-styles-wrapper', '.uicore-bl-' . $targetId, $styles);
            if (!is_array($styles_save)) {
                $styles_save = [];
            }

            // Split critical css
            $critical_inline_css = $styles_save['criticalCss'] ?? '';
            unset($styles_save['criticalCss']);

            if (!empty($fonts)) {
                $critical_inline_css .= Fonts::get_local_fonts($fonts);
            }

            $has_critical_css = !empty($critical_inline_css);
            $has_device_css =
                !empty($styles_save['mobile']) ||
                !empty($styles_save['tablet']) ||
                !empty($styles_save['desktop']) ||
                !empty($styles_save['all']);

            $has_any_css = ($has_critical_css || $has_device_css);

            if (!$has_any_css) {

                delete_post_meta($targetId, '_uicore_block_styles');
                delete_post_meta($targetId, '_uicore_block_critical_styles');
                delete_post_meta($targetId, '_uicore_block_assets');
                delete_post_meta($targetId, '_uicore_block_fonts');
                delete_post_meta($targetId, '_uicore_block_styles_version');

                \do_action('uicore_block_styles_deleted', $targetId);
            } else {

                // --- Save critical ---
                if ($has_critical_css) {
                    update_post_meta($targetId, '_uicore_block_critical_styles', $critical_inline_css);
                } else {
                    delete_post_meta($targetId, '_uicore_block_critical_styles');
                }

                // --- Save device styles ---
                if (!empty($styles_save)) {
                    update_post_meta($targetId, '_uicore_block_styles', $styles_save);
                } else {
                    delete_post_meta($targetId, '_uicore_block_styles');
                }

                update_post_meta($targetId, '_uicore_block_styles_version', time());

                \do_action('uicore_block_styles_updated', $targetId, $styles_save);

                // -------------------------
                // Preload images
                // -------------------------
                $preloadImagesData = [];
                if (!empty($preloadImages)) {
                    foreach ($preloadImages as $image) {
                        if (empty($image['src'])) {
                            continue;
                        }

                        $entry = [
                            'href'          => $image['src'],
                            'as'            => 'image',
                            'fetchpriority' => 'high',
                        ];

                        if (!empty($image['id']) && empty($image['isBg'])) {
                            $attachmentId = (int)$image['id'];

                            if ($srcset = wp_get_attachment_image_srcset($attachmentId, 'full')) {
                                $entry['imagesrcset'] = $srcset;
                            }
                            if ($sizes = wp_get_attachment_image_sizes($attachmentId, 'full')) {
                                $entry['imagesizes'] = $sizes;
                            }
                        }

                        $preloadImagesData[] = $entry;
                    }
                }

                // --- Assets ---
                $required_assets = get_post_meta($targetId, '_uicore_block_assets', true);

                if (empty($required_assets)) {
                    $required_assets = [];
                }

                $assets_update = [
                    'devices'         => [],
                    'critical_styles' => $has_critical_css,
                ];

                if (!empty($styles_save['mobile'])) {
                    $assets_update['devices'][] = 'mobile';
                }

                if (!empty($styles_save['tablet'])) {
                    $assets_update['devices'][] = 'tablet';
                }

                if (!empty($styles_save['desktop'])) {
                    $assets_update['devices'][] = 'desktop';
                }

                if (!empty($preloadImagesData)) {
                    $assets_update['preload_images'] = $preloadImagesData;
                }

                $assets_save = array_merge($required_assets, $assets_update);

                if (self::recursive_is_empty($assets_save)) {
                    delete_post_meta($targetId, '_uicore_block_assets');
                } else {
                    update_post_meta($targetId, '_uicore_block_assets', $assets_save);
                }

                // --- Fonts ---
                if (empty($fonts_save)) {
                    delete_post_meta($targetId, '_uicore_block_fonts');
                } else {
                    update_post_meta($targetId, '_uicore_block_fonts', $fonts_save);
                }
            }
        } else {

            // -------------------------
            // WIDGETS
            // -------------------------
            $styles = empty($styles) ? [] : $styles;
            $widget_css = str_replace('.editor-styles-wrapper', '.uicore-bl-styles', $styles['all'] ?? '');

            if (empty($widget_css)) {

                delete_option('_uicore_widget_block_styles_' . $targetId);
                delete_option('_uicore_widget_block_fonts_' . $targetId);
            } else {

                update_option('_uicore_widget_block_styles_' . $targetId, $widget_css);

                if (empty($fonts_save)) {
                    delete_option('_uicore_widget_block_fonts_' . $targetId);
                } else {
                    update_option('_uicore_widget_block_fonts_' . $targetId, $fonts_save);
                }
            }
        }
    }


    static function recursive_is_empty($arr)
    {
        if (!is_array($arr)) {
            return false;
        }

        foreach ($arr as $value) {
            if (is_array($value)) {
                if (!self::recursive_is_empty($value)) {
                    return false;
                }
            } else {
                if (!empty($value)) {
                    return false;
                }
            }
        }

        return true;
    }
}
