<?php

namespace FluentCrm\App\Hooks\Handlers;


use FluentCrm\App\Models\Campaign;
use FluentCrm\App\Models\FunnelCampaign;
use FluentCrm\App\Models\Meta;
use FluentCrm\App\Models\Tag;
use FluentCrm\App\Models\Template;
use FluentCrm\App\Services\BlockRender\BlockEditorHelper;
use FluentCrm\App\Services\BlockRender\CartProductData;
use FluentCrm\App\Services\Helper;
use FluentCrm\App\Services\PermissionManager;
use FluentCrm\App\Services\TransStringsGuten;
use FluentCrm\Framework\Support\Arr;

class FluentBlockEditorHandler
{
    /**
     * Data passed to the iframe editor via window.fcrmEditorBoot
     * @var array
     */
    protected $editorBootData = [];

    /*
    |--------------------------------------------------------------------------
    | Public: register(), handleEditorAutosave(), handleCartProductsListing()
    |--------------------------------------------------------------------------
    */

    public function register()
    {
        add_filter('register_block_type_args', [$this, 'registerConditionalVisibilityAttributes'], 10, 2);

        add_action('init', function () {
            register_post_type('fcrm-dummy', [
                'label'        => 'Email-Body',
                'public'       => false,
                'show_in_rest' => true,
                'supports'     => ['editor', 'thumbnail']
            ]);

            if (isset($_REQUEST['fluent_crm_block_editor'])) {
                // Require authentication
                if (!is_user_logged_in()) {
                    $scheme = is_ssl() ? 'https://' : 'http://';
                    $current_url = $scheme . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '') . (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '');
                    wp_safe_redirect(wp_login_url(esc_url_raw($current_url)));
                    exit;
                }

                // Determine required capability based on context
                $block_type = isset($_REQUEST['block_type']) ? sanitize_text_field(wp_unslash($_REQUEST['block_type'])) : '';
                $required_cap = self::getRequiredCapability($block_type);
                /**
                 * Filter the required capability for opening the FluentCRM block editor.
                 *
                 * @param string $required_cap Default capability derived from block type.
                 * @param string $block_type The requested block type.
                 * @param array $request Raw request array for advanced checks.
                 */
                $required_cap = apply_filters('fluent_crm/block_editor_required_cap', $required_cap, $block_type, $_REQUEST);

                if (!PermissionManager::currentUserCan($required_cap)) {
                    status_header(403);
                    wp_die(__('Sorry, you are not allowed to access this page.', 'fluent-crm'), 403);
                }

                // Optional nonce enforcement (off by default to preserve existing links)
                $require_nonce = (bool)apply_filters('fluent_crm/block_editor_require_nonce', false, $block_type, $_REQUEST);
                if ($require_nonce) {
                    $nonce = isset($_REQUEST['_fcrm_nonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_fcrm_nonce'])) : '';
                    if (!$nonce || !wp_verify_nonce($nonce, 'fcrm_block_editor')) {
                        status_header(403);
                        wp_die(__('Invalid or missing security token.', 'fluent-crm'), 403);
                    }
                }
                if (!defined('IFRAME_REQUEST')) {
                    define('IFRAME_REQUEST', true);
                }

                remove_action('enqueue_block_editor_assets', 'wp_enqueue_editor_block_directory_assets');
                add_action('fluent_crm/block_editor_head', function () {
                    $asset_file = FLUENTCRM_PLUGIN_PATH . 'assets/guten-editor/index.asset.php';
                    $asset      = file_exists($asset_file) ? require($asset_file) : [];
                    $version    = !empty($asset['version']) ? $asset['version'] : FLUENTCRM_PLUGIN_VERSION;
                    $url        = FLUENTCRM_PLUGIN_URL . 'assets/guten-editor/index.css';
                    ?>
                    <link rel="stylesheet"
                          href="<?php echo esc_url($url); ?>?version=<?php echo esc_attr($version); ?>"
                          media="screen"/>
                    <?php
                });

                add_filter('should_load_separate_core_block_assets', '__return_false', 20);
                $this->initializeEditor($_REQUEST); // phpcs:ignore WordPress.Security.NonceVerification.Recommended


                $actionHook = 'template_redirect';
                if(is_admin()) {
                    $actionHook = 'admin_init';
                }

                add_action($actionHook, function () {
                    $this->renderPage();
                    exit(200);
                }, -1000);

            }
        }, 2);

        // REST route for autosave
        add_action('rest_api_init', function () {
            $ns = FluentCrm()->config->get('app.rest_namespace');
            $restNamespace = $ns . '/v2';

            register_rest_route($ns . '/v1', '/editor-autosave', [
                'methods'             => 'POST',
                'callback'            => [$this, 'handleEditorAutosave'],
                'permission_callback' => function () {
                    // Basic capability check – refined per payload inside handler
                    return is_user_logged_in();
                }
            ]);

            register_rest_route($restNamespace, '/editor/cart-products', [
                'methods'             => 'GET',
                'callback'            => [$this, 'handleCartProductsListing'],
                'permission_callback' => function () {
                    return is_user_logged_in() && PermissionManager::currentUserCan('fcrm_read_emails');
                }
            ]);

            // Native REST routes for editor pattern CRUD (wp_block-compatible format)
            $patternPermission = function () {
                return is_user_logged_in() && PermissionManager::currentUserCan('fcrm_manage_email_templates');
            };

            register_rest_route($restNamespace, '/editor-patterns', [
                'methods'             => \WP_REST_Server::READABLE,
                'callback'            => [$this, 'handleEditorPatternsList'],
                'permission_callback' => $patternPermission
            ]);

            register_rest_route($restNamespace, '/editor-patterns', [
                'methods'             => \WP_REST_Server::CREATABLE,
                'callback'            => [$this, 'handleEditorPatternCreate'],
                'permission_callback' => $patternPermission
            ]);

            register_rest_route($restNamespace, '/editor-patterns/(?P<id>\d+)', [
                'methods'             => \WP_REST_Server::READABLE,
                'callback'            => [$this, 'handleEditorPatternGet'],
                'permission_callback' => $patternPermission
            ]);

            register_rest_route($restNamespace, '/editor-patterns/(?P<id>\d+)', [
                'methods'             => \WP_REST_Server::EDITABLE,
                'callback'            => [$this, 'handleEditorPatternUpdate'],
                'permission_callback' => $patternPermission
            ]);

            register_rest_route($restNamespace, '/editor-patterns/(?P<id>\d+)', [
                'methods'             => \WP_REST_Server::DELETABLE,
                'callback'            => [$this, 'handleEditorPatternDelete'],
                'permission_callback' => function () {
                    return is_user_logged_in() && PermissionManager::currentUserCan('fcrm_manage_email_delete');
                }
            ]);

            register_rest_route($restNamespace, '/editor-pattern-categories', [
                'methods'             => \WP_REST_Server::READABLE,
                'callback'            => [$this, 'handleEditorPatternCategories'],
                'permission_callback' => $patternPermission
            ]);

            register_rest_route($restNamespace, '/editor-pattern-categories', [
                'methods'             => \WP_REST_Server::CREATABLE,
                'callback'            => [$this, 'handleEditorPatternCategoryCreate'],
                'permission_callback' => $patternPermission
            ]);
        });
    }

    /**
     * Register FluentCRM conditional visibility attributes in PHP.
     *
     * WordPress validates dynamic block attributes against the server-side
     * block schema during render REST requests, so this also runs when the
     * render request contains FluentCRM's conditional visibility attributes.
     *
     * @param array  $args Block registration arguments.
     * @param string $name Block name.
     * @return array
     */
    public function registerConditionalVisibilityAttributes($args, $name)
    {
        $shouldRegister = $this->shouldRegisterConditionalVisibilityAttributes();

        if (!apply_filters('fluent_crm/block_editor_register_conditional_visibility_attributes', $shouldRegister, $name, $args)) {
            return $args;
        }

        $skipBlocks = [
            'fluentcrm/conditional-group',
            'fluent-crm/conditional-content'
        ];

        if (in_array($name, $skipBlocks, true)) {
            return $args;
        }

        if (!isset($args['attributes']) || !is_array($args['attributes'])) {
            $args['attributes'] = [];
        }

        $attributes = apply_filters('fluent_crm/block_editor_conditional_visibility_attributes', [
            'fcrmConditionType' => [
                'type'    => 'string',
                'default' => ''
            ],
            'fcrmTagIds'       => [
                'type'    => 'array',
                'default' => []
            ]
        ], $name, $args);

        foreach ((array)$attributes as $attributeName => $attributeConfig) {
            if (!isset($args['attributes'][$attributeName])) {
                $args['attributes'][$attributeName] = $attributeConfig;
            }
        }

        return $args;
    }

    /**
     * Check if the current request needs FluentCRM conditional visibility
     * attributes in server-side block schemas.
     *
     * @return bool
     */
    private function shouldRegisterConditionalVisibilityAttributes()
    {
        if (isset($_REQUEST['fluent_crm_block_editor'])) {
            return true;
        }

        if (!isset($_REQUEST['attributes'])) {
            return false;
        }

        $attributes = wp_unslash($_REQUEST['attributes']);

        if (is_array($attributes)) {
            return array_key_exists('fcrmConditionType', $attributes) || array_key_exists('fcrmTagIds', $attributes);
        }

        if (is_string($attributes)) {
            return strpos($attributes, 'fcrmConditionType') !== false || strpos($attributes, 'fcrmTagIds') !== false;
        }

        return false;
    }

    /**
     * Handle autosave requests for the block editor iframe.
     * Creates or updates campaign / recurring campaign / template records.
     * If block_type is empty and id/bid is 0, nothing will be created.
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response|\WP_Error
     */
    public function handleEditorAutosave(\WP_REST_Request $request)
    {
        $params = $request->get_json_params();
        if (!$params) {
            $params = $request->get_body_params();
        }

        $blockType = isset($params['block_type']) ? sanitize_text_field($params['block_type']) : '';
        $entityId = isset($params['id']) ? (int)$params['id'] : 0;
        $title = isset($params['title']) ? wp_strip_all_tags($params['title']) : '';
        $content = isset($params['content']) ? $params['content'] : '';
        $prevUpdatedAt = isset($params['prev_updated_at']) ? sanitize_text_field($params['prev_updated_at']) : '';
        $hash = isset($params['hash']) ? sanitize_text_field($params['hash']) : '';

        // Basic guard: if block type empty and no existing entity, do not create
        if (empty($blockType) && !$entityId) {
            return new \WP_REST_Response([
                'status'  => 'skipped',
                'message' => __('No block_type provided; nothing created.', 'fluent-crm')
            ], 200);
        }

        // Capability check
        $required_cap = self::getRequiredCapability($blockType);
        $required_cap = apply_filters('fluent_crm/block_editor_required_cap', $required_cap, $blockType, $params);
        if (!PermissionManager::currentUserCan($required_cap)) {
            return new \WP_Error('forbidden', __('You do not have permission to autosave this item', 'fluent-crm'), ['status' => 403]);
        }

        // Resolve model + field mapping
        $model = null;
        $contentField = null;
        $titleField = null;
        if ($blockType === 'campaign') {
            $model = Campaign::class;
            $contentField = 'email_body';
            $titleField = 'title';
        } elseif ($blockType === 'email_body_in_funnel') {
            $model = FunnelCampaign::class;
            $contentField = 'email_body';
            $titleField = 'title';
        } elseif ($blockType === 'recurring_campaign') {
            if (defined('FLUENTCAMPAIGN')) {
                $model = \FluentCampaign\App\Models\RecurringCampaign::class;
            }
            // Free-tier: $model stays null; the find block below uses withoutGlobalScopes() fallback.
            $contentField = 'email_body';
            $titleField = 'title';
        } elseif ($blockType === 'sequence_mail') {
            if (defined('FLUENTCAMPAIGN')) {
                $model = \FluentCampaign\App\Models\SequenceMail::class;
            }
            // Free-tier: $model stays null; the find block below uses withoutGlobalScopes() fallback.
            $contentField = 'email_body';
            $titleField = 'title';
        } elseif ($blockType === 'recurring_mail') {
            if (defined('FLUENTCAMPAIGN')) {
                $model = \FluentCampaign\App\Models\RecurringMail::class;
            }
            $contentField = 'email_body';
            $titleField = 'title';
        } elseif ($blockType === 'template') {
            $model = Template::class;
            $contentField = 'post_content';
            $titleField = 'post_title';
        } else {
            return new \WP_Error('invalid_block_type', __('Unsupported block_type', 'fluent-crm'), ['status' => 400]);
        }

        // Guard: recurring_campaign requires Pro; without it $model stays null — skip gracefully
        if ($model === null) {
            return new \WP_REST_Response([
                'status'  => 'skipped',
                'message' => __('Feature not available.', 'fluent-crm')
            ], 200);
        }

        $now = current_time('mysql');
        $created = false;
        $record = null;

        if (!$entityId) {
            return new \WP_REST_Response([
                'status'  => 'skipped',
                'message' => __('No entity ID provided.', 'fluent-crm')
            ], 200);
        }

        if ($entityId) {
            if ($model) {
                $record = $model::find($entityId);
            } else {
                // recurring_campaign on free tier: fc_campaigns with type=recurring_campaign.
                // sequence_mail on free tier: fc_campaigns with type=sequence_mail.
                // Bypass the Campaign global scope so the type filter does not exclude it.
                $record = Campaign::withoutGlobalScopes()->find($entityId);
            }
            if (!$record) {
                return new \WP_Error('not_found', __('Entity not found', 'fluent-crm'), ['status' => 404]);
            }
            // Conflict detection (always compare with model's updated_at mapping)
            if (!empty($prevUpdatedAt) && isset($record->updated_at) && $prevUpdatedAt && $prevUpdatedAt !== $record->updated_at) {
                return new \WP_REST_Response([
                    'status'            => 'conflict',
                    'id'                => $entityId,
                    'server_updated_at' => $record->updated_at,
                    'message'           => __('The item was modified elsewhere.', 'fluent-crm')
                ], 200);
            }
        }

        // Update existing record if needed
        $dirty = false;
        if ($blockType === 'template') {
            // For templates we ONLY save post_content using core wp_update_post for proper cache + hooks
            if ($record->{$contentField} !== $content) {

                $postArr = [
                    'ID'                => $entityId,
                    'post_content'      => $content,
                    'post_modified'     => current_time('mysql'),
                    'post_modified_gmt' => gmdate('Y-m-d H:i:s')
                ];
                $result = wp_update_post($postArr, true);
                if (is_wp_error($result)) {
                    return new \WP_Error('update_failed', $result->get_error_message(), ['status' => 500]);
                }
                $dirty = true;
                // Reload record to get fresh timestamps and updated content
                $record = Template::find($entityId);
            }
        } else {
            if ($record->{$contentField} !== $content) {
                $record->{$contentField} = $content;
                $dirty = true;
            }
            // Even though frontend no longer sends title for autosave, keep defensive logic (but campaign/recurring only)
            if ($title && $record->{$titleField} !== $title) {
                $record->{$titleField} = $title;
                $dirty = true;
            }
            if ($dirty) {
                try {
                    $record->save();
                } catch (\Exception $e) {
                    return new \WP_Error('update_failed', $e->getMessage(), ['status' => 500]);
                }
            }
        }

        $updatedAt = isset($record->updated_at) ? $record->updated_at : $now;

        return new \WP_REST_Response([
            'status'     => $created ? 'created' : ($dirty ? 'ok' : 'noop'),
            'id'         => $entityId,
            'hash'       => $hash,
            'updated_at' => $updatedAt,
            'saved_at'   => $now,
            'created'    => $created
        ], 200);
    }

    public function handleCartProductsListing(\WP_REST_Request $request)
    {
        $fallback = [
            'products'   => [],
            'product'    => null,
            'taxonomies' => []
        ];

        $providerResponse = apply_filters('fluent_crm/cart_products_preview_data', null, $request);
        if (is_array($providerResponse)) {
            return new \WP_REST_Response(wp_parse_args($providerResponse, $fallback), 200);
        }

        if (!defined('FLUENTCART_VERSION')) {
            return new \WP_REST_Response($fallback, 200);
        }

        $perPage = max(1, min(20, absint($request->get_param('per_page') ?: 3)));
        $order = strtolower((string)$request->get_param('order')) === 'asc' ? 'ASC' : 'DESC';
        $productId = absint($request->get_param('product_id'));
        $search = sanitize_text_field((string)$request->get_param('search'));
        if (!$productId) {
            $searchProductId = 0;
            if (preg_match('/^\s*(?:id|product_id)\s*:\s*(\d+)\s*$/i', $search, $matches)) {
                $searchProductId = absint($matches[1]);
            } elseif (preg_match('/^\s*#\s*(\d+)\s*$/', $search, $matches)) {
                $searchProductId = absint($matches[1]);
            }

            if ($searchProductId) {
                $productId = $searchProductId;
                $search = '';
            }
        }

        $taxType = sanitize_text_field((string)$request->get_param('taxType'));
        $products = CartProductData::getProducts([
            'perPage'   => $perPage,
            'order'     => $order,
            'orderBy'   => sanitize_key((string)$request->get_param('orderby')),
            'taxType'   => $taxType,
            'search'    => $search,
            'productId' => $productId,
        ], 'medium');

        $selectedProduct = ($productId && !empty($products[0])) ? $products[0] : null;

        $terms = get_terms([
            'taxonomy'   => 'product-categories',
            'hide_empty' => false
        ]);
        $termOptions = [];
        if (!is_wp_error($terms) && is_array($terms)) {
            foreach ($terms as $term) {
                $termOptions[] = [
                    'value' => (string)$term->term_id,
                    'label' => $term->name
                ];
            }
        }

        $response = [
            'products'   => $products,
            'product'    => $selectedProduct,
            'taxonomies' => [
                'product' => [
                    'terms' => [
                        'product_cat' => $termOptions
                    ]
                ]
            ]
        ];

        return new \WP_REST_Response(
            apply_filters('fluent_crm/cart_products_preview_response', $response, $request),
            200
        );
    }

    /*
    |--------------------------------------------------------------------------
    | Editor init: initializeEditor(), resolveEntityContent(),
    |              getOrCreateDummyPost(), prepareEditorBootData(), setupEditorHooks()
    |--------------------------------------------------------------------------
    */

    public function initializeEditor($data = [])
    {
        do_action('litespeed_control_set_nocache', 'fluentcrm api request');
        // set no cache headers
        nocache_headers();

        $context = Arr::get($data, 'block_type'); // campaign or template etc ..
        $this->unregisterDefaultBlockPatterns($context, $data);

        // Double-check permissions inside renderer based on context
        $required_cap = self::getRequiredCapability($context);
        $required_cap = apply_filters('fluent_crm/block_editor_required_cap', $required_cap, $context, $data);
        $hasAccess = PermissionManager::currentUserCan($required_cap);

        $entity = $this->resolveEntityContent($context, $data);

        if (!$hasAccess) {
            echo '<h3 style="padding: 100px; text-align: center;">' . esc_html__('Sorry, you do not have access to this page.', 'fluent-crm') . '</h3>';
            exit(200);
        }

        add_filter('should_load_separate_core_block_assets', '__return_false', 20);
        show_admin_bar(false);

        global $post;
        $post = $this->getOrCreateDummyPost($entity['title'], $entity['content']);

        $this->prepareEditorBootData($context, $data, $entity);
        $this->setupEditorHooks($post);
    }

    /**
     * Resolve entity content from the database based on block_type and bid.
     *
     * @param string $context The block_type (campaign, recurring_campaign, template).
     * @param array $data The request data.
     * @return array With keys: content, title, id, updatedAt, availableTags.
     */
    private function resolveEntityContent($context, $data)
    {
        $post_content = '<!-- wp:paragraph --><p></p><!-- /wp:paragraph -->';
        $post_title = 'Demo Title';
        $recordId = null;
        $recordUpdatedAt = current_time('mysql');
        $availableTags = [];

        if ($context == 'campaign') {
            $campaignId = (int)Arr::get($data, 'bid');
            if ($campaignId && $campaignId != 'undefined') {
                $campaign = Campaign::find($campaignId);
                if ($campaign) {
                    $post_content = $campaign->email_body;
                    $post_title = $campaign->title;
                    $recordId = $campaign->id;
                    $recordUpdatedAt = isset($campaign->updated_at) ? $campaign->updated_at : $recordUpdatedAt;
                }
            }
        }

        if ($context == 'email_body_in_funnel') {
            $campaignId = (int)Arr::get($data, 'bid');
            if ($campaignId && $campaignId != 'undefined') {
                $campaign = FunnelCampaign::find($campaignId);
                if ($campaign) {
                    $post_content = $campaign->email_body;
                    $post_title = $campaign->title;
                    $recordId = $campaign->id;
                    $recordUpdatedAt = isset($campaign->updated_at) ? $campaign->updated_at : $recordUpdatedAt;
                }
            }
        }

        // Pro Required for Recurring Campaigns
        if (defined('FLUENTCAMPAIGN')) {

            if ($context == 'recurring_campaign') {
                $campaign = null;
                $campaignId = (int)Arr::get($data, 'bid');
                if ($campaignId && $campaignId != 'undefined') {
                    $campaign = \FluentCampaign\App\Models\RecurringCampaign::find($campaignId);
                }
                // Fallback for free-tier Email Sequences stored in fc_campaigns with type=recurring_campaign.
                if (!$campaign && $campaignId) {
                    $campaign = Campaign::withoutGlobalScopes()->find($campaignId);
                }
                if ($campaign) {
                    $post_content = $campaign->email_body;
                    $post_title = $campaign->title;
                    $recordId = $campaign->id;
                    $recordUpdatedAt = isset($campaign->updated_at) ? $campaign->updated_at : $recordUpdatedAt;
                }
            }

            if ($context == 'recurring_mail') {
                $mailId = (int)Arr::get($data, 'bid');
                if ($mailId && $mailId != 'undefined') {
                    $mail = \FluentCampaign\App\Models\RecurringMail::find($mailId);
                    if ($mail) {
                        $post_content = $mail->email_body;
                        $post_title = $mail->title;
                        $recordId = $mail->id;
                        $recordUpdatedAt = isset($mail->updated_at) ? $mail->updated_at : $recordUpdatedAt;
                    }
                }
            }

            if ($context == 'sequence_mail') {
                $mail = null;
                $mailId = (int)Arr::get($data, 'bid');
                if ($mailId && $mailId != 'undefined') {
                    $mail = \FluentCampaign\App\Models\SequenceMail::find($mailId);
                }
                // Fallback for free-tier Email Sequences stored in fc_campaigns with type=sequence_mail.
                if (!$mail && $mailId) {
                    $mail = Campaign::withoutGlobalScopes()->find($mailId);
                }
                if ($mail) {
                    $post_content = $mail->email_body;
                    $post_title = $mail->title;
                    $recordId = $mail->id;
                    $recordUpdatedAt = isset($mail->updated_at) ? $mail->updated_at : $recordUpdatedAt;
                }
            }
        }

        if ($context == 'template') {
            $templateId = (int)Arr::get($data, 'bid');
            if ($templateId && $templateId != 'undefined') {
                $template = Template::find($templateId);
                if ($template) {
                    $post_content = $template->post_content;
                    $post_title = $template->post_title;
                    $recordId = $templateId;
                    $recordUpdatedAt = isset($template->updated_at) ? $template->updated_at : $recordUpdatedAt;
                }
            }
        }

        if ($context == 'email_pattern') {
            $patternId = (int)Arr::get($data, 'bid');
            if ($patternId && $patternId != 'undefined') {
                $pattern = Meta::where('object_type', 'email_pattern')->where('id', $patternId)->first();
                if ($pattern) {
                    $post_content = Arr::get($pattern->value, 'content', '');
                    $post_title = Arr::get($pattern->value, 'title', '');
                    $recordId = $pattern->id;
                    $recordUpdatedAt = $pattern->updated_at ?: $recordUpdatedAt;
                }
            }
        }

        try {
            $availableTags = Tag::select(['id', 'title'])->orderBy('title', 'ASC')->get();
        } catch (\Throwable $e) {
            $availableTags = [];
        }

        if (!$post_content) {
            $post_content = '<!-- wp:paragraph --><p></p><!-- /wp:paragraph -->';
        }

        return [
            'content'       => $post_content,
            'title'         => $post_title,
            'id'            => $recordId,
            'updatedAt'     => $recordUpdatedAt,
            'availableTags' => $availableTags,
        ];
    }

    /**
     * Retrieve or create the fcrm-dummy post used as a simulated post for the editor.
     *
     * @param string $title
     * @param string $content
     * @return \WP_Post
     */
    private function getOrCreateDummyPost($title, $content)
    {
        $firstPost = fluentCrmDb()->table('posts')
            ->where('post_type', 'fcrm-dummy')
            ->first();

        if ($firstPost) {
            $simulatedPost = get_post($firstPost->ID);
            $simulatedPost->post_content = $content;
            $simulatedPost->post_title = $title;
        } else {
            $newPostId = wp_insert_post(array(
                'post_title'   => $title,
                'post_content' => $content,
                'post_type'    => 'fcrm-dummy',
                'post_status'  => 'draft',
            ));

            $simulatedPost = get_post($newPostId);
        }

        return $simulatedPost;
    }

    /*
     * -----------------------------------------------------------------------
     * Native REST handlers for editor patterns (wp_block-compatible format).
     * These bypass WPFluent's response pipeline so core-data gets raw responses.
     * -----------------------------------------------------------------------
     */

    public function handleEditorPatternsList()
    {
        $patterns = Meta::where('object_type', 'email_pattern')
            ->orderBy('id', 'desc')
            ->get();

        $categoryMap = $this->getPatternCategoryMap();
        $items = [];
        foreach ($patterns as $pattern) {
            $items[] = $this->formatMetaAsWpBlock($pattern, $categoryMap);
        }

        return new \WP_REST_Response($items, 200);
    }

    public function handleEditorPatternGet(\WP_REST_Request $request)
    {
        $id = (int) $request->get_param('id');
        $pattern = Meta::where('object_type', 'email_pattern')->where('id', $id)->first();

        if (!$pattern) {
            return new \WP_Error('not_found', __('Pattern not found', 'fluent-crm'), ['status' => 404]);
        }

        $categoryMap = $this->getPatternCategoryMap();
        return new \WP_REST_Response($this->formatMetaAsWpBlock($pattern, $categoryMap), 200);
    }

    public function handleEditorPatternCreate(\WP_REST_Request $request)
    {
        $params = $request->get_json_params();
        if (empty($params)) {
            $params = $request->get_body_params();
        }

        $title = Arr::get($params, 'title', '');
        if (is_array($title)) {
            $title = Arr::get($title, 'raw', '');
        }
        $title = sanitize_text_field($title);

        $content = Arr::get($params, 'content', '');
        if (is_array($content)) {
            $content = Arr::get($content, 'raw', '');
        }
        $content = wp_kses_post($content);

        if (!$title) {
            $title = __('Untitled Pattern', 'fluent-crm');
        }

        $meta = Arr::get($params, 'meta', []);
        $syncStatus = is_array($meta) ? sanitize_text_field(Arr::get($meta, 'wp_pattern_sync_status', '')) : '';

        $categoryIds = (array) Arr::get($params, 'wp_pattern_category', []);
        $categoryName = $this->resolvePatternCategoryName($categoryIds);

        $slug = 'fluentcrm/' . sanitize_title($title . '-' . uniqid());

        $pattern = Meta::create([
            'object_type' => 'email_pattern',
            'object_id'   => get_current_user_id(),
            'key'         => $slug,
            'value'       => [
                'title'       => $title,
                'content'     => $content,
                'category'    => $categoryName,
                'description' => '',
                'sync_status' => $syncStatus,
            ],
        ]);

        $categoryMap = $this->getPatternCategoryMap();
        return new \WP_REST_Response($this->formatMetaAsWpBlock($pattern, $categoryMap), 201);
    }

    public function handleEditorPatternUpdate(\WP_REST_Request $request)
    {
        $id = (int) $request->get_param('id');
        $pattern = Meta::where('object_type', 'email_pattern')->where('id', $id)->first();

        if (!$pattern) {
            return new \WP_Error('not_found', __('Pattern not found', 'fluent-crm'), ['status' => 404]);
        }

        $params = $request->get_json_params();
        if (empty($params)) {
            $params = $request->get_body_params();
        }

        $value = $pattern->value;

        $title = Arr::get($params, 'title');
        if ($title !== null) {
            if (is_array($title)) {
                $title = Arr::get($title, 'raw', '');
            }
            $value['title'] = sanitize_text_field($title);
        }

        $content = Arr::get($params, 'content');
        if ($content !== null) {
            if (is_array($content)) {
                $content = Arr::get($content, 'raw', '');
            }
            $value['content'] = wp_kses_post($content);
        }

        $meta = Arr::get($params, 'meta', []);
        if (is_array($meta) && isset($meta['wp_pattern_sync_status'])) {
            $value['sync_status'] = sanitize_text_field($meta['wp_pattern_sync_status']);
        }

        $categoryIds = Arr::get($params, 'wp_pattern_category');
        if ($categoryIds !== null) {
            $value['category'] = $this->resolvePatternCategoryName((array) $categoryIds);
        }

        $pattern->value = $value;
        $pattern->save();

        $categoryMap = $this->getPatternCategoryMap();
        return new \WP_REST_Response($this->formatMetaAsWpBlock($pattern, $categoryMap), 200);
    }

    public function handleEditorPatternDelete(\WP_REST_Request $request)
    {
        $id = (int) $request->get_param('id');
        $pattern = Meta::where('object_type', 'email_pattern')->where('id', $id)->first();

        if (!$pattern) {
            return new \WP_Error('not_found', __('Pattern not found', 'fluent-crm'), ['status' => 404]);
        }

        $response = $this->formatMetaAsWpBlock($pattern, $this->getPatternCategoryMap());
        $pattern->delete();

        return new \WP_REST_Response($response, 200);
    }

    public function handleEditorPatternCategories()
    {
        $categories = Meta::where('object_type', 'email_pattern_category')
            ->orderBy('id', 'asc')
            ->get();

        $items = [];
        foreach ($categories as $cat) {
            $items[] = [
                'id'     => (int) $cat->id,
                'count'  => 0,
                'name'   => Arr::get($cat->value, 'name', $cat->key),
                'slug'   => $cat->key,
                'parent' => 0,
            ];
        }

        return new \WP_REST_Response($items, 200);
    }

    public function handleEditorPatternCategoryCreate(\WP_REST_Request $request)
    {
        $params = $request->get_json_params();
        if (empty($params)) {
            $params = $request->get_body_params();
        }

        $name = sanitize_text_field(Arr::get($params, 'name', ''));
        if (!$name) {
            return new \WP_Error('missing_name', __('Category name is required', 'fluent-crm'), ['status' => 400]);
        }

        $slug = sanitize_title($name);
        $existing = Meta::where('object_type', 'email_pattern_category')->where('key', $slug)->first();

        if ($existing) {
            return new \WP_REST_Response([
                'id'     => (int) $existing->id,
                'count'  => 0,
                'name'   => Arr::get($existing->value, 'name', $existing->key),
                'slug'   => $existing->key,
                'parent' => 0,
            ], 200);
        }

        $category = Meta::create([
            'object_type' => 'email_pattern_category',
            'object_id'   => 0,
            'key'         => $slug,
            'value'       => ['name' => $name],
        ]);

        return new \WP_REST_Response([
            'id'     => (int) $category->id,
            'count'  => 0,
            'name'   => $name,
            'slug'   => $slug,
            'parent' => 0,
        ], 201);
    }

    private function formatMetaAsWpBlock($meta, $categoryMap = [])
    {
        $value = $meta->value;
        $title = Arr::get($value, 'title', '');
        $content = Arr::get($value, 'content', '');
        $syncStatus = Arr::get($value, 'sync_status', 'unsynced');
        $category = Arr::get($value, 'category', '');

        $categoryIds = [];
        if ($category) {
            $catSlug = sanitize_title($category);
            if (isset($categoryMap[$catSlug])) {
                $categoryIds[] = (int) $categoryMap[$catSlug];
            }
        }

        return [
            'id'                     => (int) $meta->id,
            'date'                   => $meta->created_at ?: gmdate('Y-m-d\TH:i:s'),
            'date_gmt'               => $meta->created_at ?: gmdate('Y-m-d\TH:i:s'),
            'modified'               => $meta->updated_at ?: gmdate('Y-m-d\TH:i:s'),
            'modified_gmt'           => $meta->updated_at ?: gmdate('Y-m-d\TH:i:s'),
            'slug'                   => $meta->key,
            'status'                 => 'publish',
            'type'                   => 'wp_block',
            'link'                   => '',
            'title'                  => ['raw' => $title],
            'content'                => ['raw' => $content, 'protected' => false],
            'meta'                   => new \stdClass(),
            'wp_pattern_sync_status' => $syncStatus ?: '',
            'wp_pattern_category'    => $categoryIds,
        ];
    }

    private function getPatternCategoryMap()
    {
        $categories = Meta::where('object_type', 'email_pattern_category')->get();
        $map = [];
        foreach ($categories as $cat) {
            $map[$cat->key] = $cat->id;
        }
        return $map;
    }

    private function resolvePatternCategoryName($categoryIds)
    {
        if (empty($categoryIds)) {
            return '';
        }
        $categoryIds = array_map('intval', $categoryIds);
        $category = Meta::where('object_type', 'email_pattern_category')
            ->whereIn('id', $categoryIds)
            ->first();

        return $category ? Arr::get($category->value, 'name', $category->key) : '';
    }

    /**
     * Build the editorBootData array that is injected into the iframe as window.fcrmEditorBoot.
     *
     * @param string $context
     * @param array $data
     * @param array $entity Return value from resolveEntityContent().
     */
    private function prepareEditorBootData($context, $data, $entity)
    {
        $canSave = (!empty($context) && $context !== '0');
        // If block_type null/empty and bid == 0 we won't create anything (flag can_save false)
        if (empty($context) && (int)Arr::get($data, 'bid') === 0) {
            $canSave = false;
        }
        // New templates (id=0) should not autosave until they are explicitly created.
        if ($context === 'template' && (int)Arr::get($data, 'bid') === 0) {
            $canSave = false;
        }
        $hideBackBtn = self::parseBoolParam(Arr::get($data, 'hideBackBtn', Arr::get($data, 'hide_back_btn', false)));
        $hideNextBtn = self::parseBoolParam(Arr::get($data, 'hideNextBtn', Arr::get($data, 'hide_next_btn', false)));
        $hideSaveBtn = self::parseBoolParam(Arr::get($data, 'hideSaveBtn', Arr::get($data, 'hide_save_btn', false)));
        $disableAutosave = self::parseBoolParam(Arr::get($data, 'disableAutosave', Arr::get($data, 'disable_autosave', false)));
        if ($disableAutosave) {
            $canSave = false;
        }
        // Load user-saved email patterns from the database
        $savedPatternData = \FluentCrm\App\Http\Controllers\EmailPatternController::getEditorPatterns();
        $savedPatterns = $savedPatternData['patterns'];
        $savedPatternCategories = $savedPatternData['categories'];

        $customPatterns = apply_filters('fluent_crm/block_editor_custom_patterns', $savedPatterns, $context, $data);
        if (!is_array($customPatterns)) {
            $customPatterns = [];
        }
        $customPatternCategories = apply_filters('fluent_crm/block_editor_custom_pattern_categories', $savedPatternCategories, $context, $data);
        if (!is_array($customPatternCategories)) {
            $customPatternCategories = [];
        }
        $designTemplate = isset($data['design_template']) ? sanitize_text_field($data['design_template']) : '';
        $features = $this->getEditorFeatures($context);
        $this->editorBootData = [
            'entity'                  => [
                'id'         => $entity['id'],
                'block_type' => $context,
                'title'      => $entity['title'],
                'content'    => $entity['content'],
                'updated_at' => $entity['updatedAt'],
            ],
            'can_save'                => $canSave,
            'autosave'                => [
                'endpoint' => rest_url(FluentCrm()->config->get('app.rest_namespace') . '/v1/editor-autosave'),
                'nonce'    => wp_create_nonce('wp_rest')
            ],
            'fcrm_ui'                 => isset($data['fcrm_ui']) ? sanitize_text_field($data['fcrm_ui']) : '',
            'compose_nav'             => [
                'hideBackBtn'    => $hideBackBtn,
                'hideNextBtn'    => $hideNextBtn,
                'hideSaveBtn'    => $hideSaveBtn
            ],
            'email_template_designs'  => \FluentCrm\App\Services\Helper::getEmailDesignTemplates(),
            'current_design_template' => $designTemplate,
            'available_tags'          => $entity['availableTags'],
            'global_email_footer'     => \FluentCrm\App\Services\Helper::getEmailFooterContent(),
            'more_menu'               => [
                'help_url'             => apply_filters('fluent_crm/block_editor_help_url', 'https://fluentcrm.com/docs/'),
                'patterns_url'         => apply_filters('fluent_crm/block_editor_patterns_url', admin_url('edit.php?post_type=wp_block')),
                'hide_welcome_guide'   => (bool)apply_filters('fluent_crm/block_editor_hide_welcome_guide', true),
                'hide_manage_patterns' => (bool)apply_filters('fluent_crm/block_editor_hide_manage_patterns', true),
                'replace_native_help'  => (bool)apply_filters('fluent_crm/block_editor_replace_native_help', true),
            ],
            'patterns'                => [
                'unregister_all' => (bool)apply_filters('fluent_crm/block_editor_unregister_all_patterns', true, $context, $data),
                'custom'         => array_values($customPatterns),
                'categories'     => array_values($customPatternCategories),
            ],
            'ai_writing'              => $this->getAiWritingConfig(),
            'features'                => $features,
        ];
    }

    /**
     * Get editor feature flags based on content type.
     * This is the single source of truth for which UI elements show per context.
     *
     * @param string $context  block_type: campaign, template, email_pattern, recurring_campaign, sequence_mail, email_body_in_funnel
     * @return array
     */
    private function getEditorFeatures($context)
    {
        // Full email editing features (default for campaigns, templates, etc.)
        $emailDefaults = [
            'email_style_settings' => true,
            'email_footer'         => true,
            'email_preview'        => true,
            'save_as_template'     => true,
            'browse_templates'     => true,
            'smartcodes'           => true,
            'design_switcher'      => true,
            'save_draft'           => true,
        ];

        // Minimal features for non-email content (patterns, snippets, etc.)
        $minimalDefaults = [
            'email_style_settings' => false,
            'email_footer'         => false,
            'email_preview'        => true,
            'save_as_template'     => false,
            'browse_templates'     => false,
            'smartcodes'           => false,
            'design_switcher'      => false,
            'switch_editor'        => false,
            'create_pattern'       => false,
            'save_draft'           => true,
            'sidebar_panel_title'  => __('Pattern Info', 'fluent-crm'),
            'sidebar_content'      => '<h3>' . __('Editing Pattern', 'fluent-crm') . '</h3>'
                . '<p>' . __('Patterns are reusable block layouts that can be inserted into any email. Changes here will apply to all future emails that use this pattern.', 'fluent-crm') . '</p>'
                . '<p>' . __('Synced patterns stay linked — editing here updates everywhere. Unsynced patterns are copied on insert.', 'fluent-crm') . '</p>',
        ];

        $presets = [
            'campaign'              => $emailDefaults,
            'template'              => $emailDefaults,
            'recurring_campaign'    => $emailDefaults,
            'recurring_mail'        => $emailDefaults,
            'sequence_mail'         => $emailDefaults,
            'email_body_in_funnel'  => $emailDefaults,
            'email_pattern'         => $minimalDefaults,
        ];

        $features = isset($presets[$context]) ? $presets[$context] : $emailDefaults;

        return apply_filters('fluent_crm/block_editor_features', $features, $context);
    }

    private function getAiWritingConfig()
    {
        $credentials = get_option('_fluent_ai_creds', []);
        $preferences = fluentcrm_get_option('_ai_writing_settings', []);

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

        $provider = isset($credentials['provider']) ? $credentials['provider'] : '';
        $hasApiKey = !empty($credentials['api_key']) || $provider === 'wordpress';

        return [
            'enabled' => (
                is_array($credentials)
                && is_array($preferences)
                && isset($preferences['is_enabled'])
                && $preferences['is_enabled'] === 'yes'
                && $hasApiKey
                && !empty($credentials['provider'])
                && !empty($credentials['model'])
            ),
        ];
    }

    /**
     * Register wp_enqueue_scripts callbacks, post-locking filters, and other editor hooks.
     *
     * @param \WP_Post $post
     */
    private function setupEditorHooks($post)
    {
        $enqueueHook = 'wp_enqueue_scripts';

        add_action($enqueueHook, function () use ($post) {
            wp_enqueue_script('postbox', admin_url('js/postbox.min.js'), array('jquery-ui-sortable'), false, 1);
            wp_enqueue_editor();
            wp_enqueue_script('wp-tinymce');
            wp_enqueue_style('dashicons');
            wp_enqueue_style('media');
            wp_enqueue_style('admin-menu');
            wp_enqueue_style('admin-bar');
            wp_enqueue_style('l10n');

            wp_add_inline_script(
                'wp-api-fetch',
                \sprintf(
                    'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );',
                    wp_json_encode(
                        array(
                            '/wp/v2/fcrm-dummy/' . $post->ID . '?context=edit' => array(
                                'body' => array(
                                    'id'                 => $post->ID,
                                    'title'              => array('raw' => $post->post_title),
                                    'content'            => array(
                                        'block_format' => 1,
                                        'raw'          => $post->post_content,
                                    ),
                                    'excerpt'            => array('raw' => ''),
                                    'date'               => '',
                                    'date_gmt'           => '',
                                    'modified'           => '',
                                    'modified_gmt'       => '',
                                    'link'               => home_url('/'),
                                    'guid'               => array(),
                                    'parent'             => 0,
                                    'menu_order'         => 0,
                                    'author'             => 0,
                                    'featured_media'     => 0,
                                    'comment_status'     => 'closed',
                                    'ping_status'        => 'closed',
                                    'template'           => '',
                                    'meta'               => array(),
                                    '_links'             => array(),
                                    'type'               => 'fcrm-dummy',
                                    'status'             => 'pending', // pending is the best state to remove draft saving possibilities.
                                    'slug'               => '',
                                    'generated_slug'     => '',
                                    'permalink_template' => home_url('/'),
                                ),
                            ),
                        )
                    )
                ),
                'after'
            );
        }, 11);

        add_action($enqueueHook, function ($hook) use ($post) {
            // Gutenberg requires the post-locking functions defined within:
            // See `show_post_locked_dialog` and `get_post_metadata` filters below.
            include_once ABSPATH . 'wp-admin/includes/post.php';
            $this->enqueueEditorAssets($hook, $post);
        });

        // Disable post locking dialogue.
        add_filter('show_post_locked_dialog', '__return_false');

        // Everyone can richedit! This avoids a case where a page can be cached where a user can't richedit.
        $GLOBALS['wp_rich_edit'] = true;
        add_filter('user_can_richedit', '__return_true', 1000);

        // This prevents other logged-in users taking a lock of the post on the front-end.
        add_filter('get_post_metadata', function ($value, $post_id, $meta_key) {
            if ($meta_key !== '_edit_lock') {
                return $value;
            }
            return time() . ':' . get_current_user_id();
        }, 10, 3);

        // Disable Jetpack Blocks for now.
        add_filter('jetpack_gutenberg', '__return_false');
    }

    /*
    |--------------------------------------------------------------------------
    | Assets: enqueueEditorAssets(), enqueueEditorScripts(),
    |         enqueueEditorStyles(), enqueueCustomEditorAssets()
    |--------------------------------------------------------------------------
    */

    private function enqueueEditorAssets($hook, $post)
    {

        $initial_edits = array(
            'title'   => $post->post_title,
            'content' => $post->post_content,
            'excerpt' => $post->post_excerpt,
        );

        $editor_settings = $this->getEditorSettings($post);

        $init_script = <<<JS
			( function() {
				window._wpLoadBlockEditor = new Promise( function( resolve, reject ) {
					wp.domReady( function() {
						try {
							resolve( wp.editPost.initializeEditor( 'editor', "%s", %d, %s, %s ) );
						} catch (e) {
							console.error('[FCRM Editor] initializeEditor failed:', e);
							reject(e);
						}
					} );
				} );
			} )();
			JS;

        $script = sprintf(
            $init_script,
            $post->post_type,
            $post->ID,
            wp_json_encode($editor_settings),
            wp_json_encode($initial_edits)
        );
        wp_add_inline_script('wp-edit-post', $script);

        $this->enqueueEditorScripts($post);
        $this->enqueueEditorStyles();
        $this->enqueueCustomEditorAssets();
    }

    /**
     * Enqueue media, tinymce, and postbox init scripts.
     *
     * @param \WP_Post $post
     */
    private function enqueueEditorScripts($post)
    {
        wp_enqueue_media(
            array(
                'post' => null
            )
        );

        add_filter('user_can_richedit', '__return_true');
        wp_tinymce_inline_scripts();
        wp_enqueue_editor();
        wp_enqueue_script('wp-tinymce');
    }

    /**
     * Enqueue wp-edit-post, block library styles, and editor format library assets.
     */
    private function enqueueEditorStyles()
    {
        wp_enqueue_style('wp-edit-post');

        /*
        These styles are usually registered by Gutenberg and register properly when the user is signed in.
        However, if the use is not registered they are not added. For now, include them, but this isn't a good long term strategy

        See: https://github.com/WordPress/wporg-gutenberg/issues/26
        */
        wp_enqueue_style('wp-block-library');
        wp_enqueue_style('wp-block-image');
        wp_enqueue_style('wp-block-group');
        wp_enqueue_style('wp-block-heading');
        wp_enqueue_style('wp-block-button');
        wp_enqueue_style('wp-block-paragraph');
        wp_enqueue_style('wp-block-separator');
        wp_enqueue_style('wp-block-columns');
        wp_enqueue_style('wp-block-row');
        wp_enqueue_style('wp-block-cover');
        wp_enqueue_style('wp-block-spacer');

        wp_register_style('fluent_crm_editor_styles', FLUENTCRM_PLUGIN_URL . 'assets/guten-editor/style.css', false, FLUENTCRM_PLUGIN_VERSION, 'all');

        add_action('fluent_enqueue_block_editor_assets', 'wp_enqueue_editor_format_library_assets');

        /**
         * Fires after block assets have been enqueued for the editing interface.
         *
         * Call `add_action` on any hook before 'admin_enqueue_scripts'.
         *
         * In the function call you supply, simply use `wp_enqueue_script` and
         * `wp_enqueue_style` to add your functionality to the Gutenberg editor.
         *
         * @since 0.4.0
         */
        do_action('fluent_enqueue_block_editor_assets');
    }

    /**
     * Enqueue fcrm_editor_custom JS, inline block editor config, smartcodes, and boot data.
     */
    private function enqueueCustomEditorAssets()
    {
        $editor_asset_file = FLUENTCRM_PLUGIN_PATH . 'assets/guten-editor/index.asset.php';
        $editor_asset      = file_exists($editor_asset_file) ? require($editor_asset_file) : [];
        $editor_deps       = !empty($editor_asset['dependencies']) ? $editor_asset['dependencies'] : ['react', 'wp-edit-post', 'wp-plugins'];
        $editor_version    = !empty($editor_asset['version']) ? $editor_asset['version'] : FLUENTCRM_PLUGIN_VERSION;
        if (!in_array('wp-edit-post', $editor_deps)) {
            $editor_deps[] = 'wp-edit-post';
        }
        if (!in_array('wp-reusable-blocks', $editor_deps)) {
            $editor_deps[] = 'wp-reusable-blocks';
        }
        wp_enqueue_script('fcrm_editor_custom', FLUENTCRM_PLUGIN_URL . 'assets/guten-editor/index.js', $editor_deps, $editor_version, true);

        $availableDesigns = Helper::getEmailDesignTemplates();
        $availableDesigns = array_filter($availableDesigns, function ($design) {
            return !empty($design['use_gutenberg']);
        });
        $designPresetPayloads = [];
        foreach ($availableDesigns as $designKey => $design) {
            $designPresetPayloads[$designKey] = $design;
            $designPresetPayloads[$designKey]['config'] = [
                'design_template' => Arr::get($design, 'id', $designKey)
            ];
        }

        // Namespaced REST routes for the editor bundle; namespace follows FLUENTCRM_REST_NAMESPACE
        $ns = FluentCrm()->config->get('app.rest_namespace') . '/v2';

        $blockEditorConfig = [
            'modules'                 => [
                'hasWooCommerce'    => defined('WC_PLUGIN_FILE'),
                'hasFluentCampaign' => defined('FLUENTCAMPAIGN'),
                'hasFluentCart'     => defined('FLUENTCART_VERSION')
            ],
            'endpoints'               => [
                'aiGenerate'          => $ns . '/ai/generate',
                'aiGenerateEmailBody' => $ns . '/ai/generate-email-body',
                'posts'               => $ns . '/campaigns-pro/posts',
                'postTaxonomies'      => $ns . '/campaigns-pro/posts/taxonomies',
                'products'            => apply_filters('fluent_crm/block_editor_products_endpoint', $ns . '/campaigns-pro/products'),
                'cartProducts'        => apply_filters('fluent_crm/block_editor_cart_products_endpoint', $ns . '/editor/cart-products'),
                'patterns'            => $ns . '/editor-patterns',
                'patternCategories'   => $ns . '/editor-pattern-categories',
                'smartLinks'          => $ns . '/smart-links',
                'tags'                => apply_filters('fluent_crm/block_editor_tags_endpoint', $ns . '/reports/options?fields=tags')
            ],
            'fontSizes'               => BlockEditorHelper::getDefaultPreset('font-size'),
            'spacingPresets'          => BlockEditorHelper::getDefaultPreset('spacing'),
            'defaultDesignConfig'     => Helper::getTemplateConfig(false),
            // Keep the shared design metadata intact for legacy consumers while ensuring
            // Gutenberg preset clicks only change the selected design template.
            'designTemplatePresets'   => $designPresetPayloads,
            'default_design_template' => Helper::getDefaultEmailTemplate()
        ];

        wp_add_inline_script(
            'fcrm_editor_custom',
            'window.fcrmBlockEditorConfig = ' . wp_json_encode($blockEditorConfig) . ';',
            'before'
        );

        // Inject smartcodes into the iframe window
        $globalSmartCodes = Helper::getGlobalSmartCodes();
        $extendedSmartCodes = Helper::getExtendedSmartCodes();
        $transStrings = TransStringsGuten::getStrings();
        wp_add_inline_script(
            'fcrm_editor_custom',
            'window.fcAdmin = window.fcAdmin || {};' .
            'window.fcAdmin.globalSmartCodes = ' . wp_json_encode($globalSmartCodes) . ';' .
            'window.fcAdmin.extendedSmartCodes = ' . wp_json_encode($extendedSmartCodes) . ';' .
            'window.fcAdmin.trans = Object.assign({}, window.fcAdmin.trans || {}, ' . wp_json_encode($transStrings) . ');',
            'before'
        );

        if (!empty($this->editorBootData)) {
            wp_add_inline_script(
                'fcrm_editor_custom',
                'window.fcrmEditorBoot = ' . wp_json_encode($this->editorBootData) . ';',
                'before'
            );
        }
    }

    /*
    |--------------------------------------------------------------------------
    | Settings: getEditorSettings(), getAllowedBlocks(), getEditorStyleSheets(),
    |           getResolvedAssets(), getDefaultEditorStyles()
    |--------------------------------------------------------------------------
    */

    private function getEditorSettings($post)
    {
        // Run pattern cleanup here as well (late) so theme/plugin init hooks cannot re-add defaults.
        $context = Arr::get($this->editorBootData, 'entity.block_type', '');
        $requestData = is_array($_REQUEST) ? $_REQUEST : [];
        $this->unregisterDefaultBlockPatterns($context, $requestData);

        // Media settings.
        $max_upload_size = wp_max_upload_size();
        if (!$max_upload_size) {
            $max_upload_size = 0;
        }

        $lock_details = array(
            'isLocked' => false,
            'user'     => '',
        );

        $allowedBlocks = $this->getAllowedBlocks();

        $blockStyleDefaults = BlockEditorHelper::getStyleDefauls();


        $editor_settings = array(
            'maxUploadFileSize'                => $max_upload_size,
            'allowedMimeTypes'                 => get_allowed_mime_types(),
            'postLock'                         => $lock_details,
            'postLockUtils'                    => array(
                'nonce'       => wp_create_nonce('lock-post_' . $post->ID),
                'unlockNonce' => wp_create_nonce('update-post_' . $post->ID),
                'ajaxUrl'     => admin_url('admin-ajax.php'),
            ),
            '__experimentalFeatures'           => array(
                'appearanceTools'               => true,
                'useRootPaddingAwareAlignments' => false,
                'border'                        => [
                    'color'  => 1,
                    'radius' => 1,
                    'style'  => 1,
                    'width'  => 1,
                ],
                'color'                         => [
                    'background'       => true,
                    'button'           => 1,
                    'caption'          => 1,
                    'customDuotone'    => 0,
                    'defaultDuotone'   => 0,
                    'defaultGradients' => 0,
                    'defaultPalette'   => true,
                    'duotone'          => [],
                    'gradients'        => [],
                    'heading'          => 1,
                    'link'             => 1,
                    'palette'          => [
                        'default' => $blockStyleDefaults['color'],
                    ],
                    'text'             => true,
                ],
                'dimensions'                    => [
                    'units'               => ['px'],
                    'defaultAspectRatios' => false,
                    'aspectRatio'         => false,
                    'minHeight'           => 1,
                ],
                'shadow'                        => [
                    'defaultPresets' => true,
                    'presets'        => [
                        'default' => [
                            [
                                'name'   => 'Natural',
                                'slug'   => 'natural',
                                'shadow' => '6px 6px 9px rgba(0, 0, 0, 0.2)',
                            ],
                            [
                                'name'   => 'Deep',
                                'slug'   => 'deep',
                                'shadow' => '12px 12px 50px rgba(0, 0, 0, 0.4)',
                            ],
                            [
                                'name'   => 'Sharp',
                                'slug'   => 'sharp',
                                'shadow' => '6px 6px 0px rgba(0, 0, 0, 0.2)',
                            ],
                            [
                                'name'   => 'Outlined',
                                'slug'   => 'outlined',
                                'shadow' => '6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1)',
                            ],
                            [
                                'name'   => 'Crisp',
                                'slug'   => 'crisp',
                                'shadow' => '6px 6px 0px rgba(0, 0, 0, 1)',
                            ],
                        ],
                    ],
                ],
                'spacing'                       => [
                    'blockGap'            => 1,
                    'margin'              => 1,
                    'padding'             => 1,
                    'units'               => ['px'],
                    'defaultSpacingSizes' => true,
                    'spacingScale'        => [
                        'default' => [
                            'operator'   => '*',
                            'increment'  => 1.5,
                            'steps'      => 7,
                            'mediumStep' => 24,
                            'unit'       => 'px',
                        ],
                    ],
                    'spacingSizes'        => [
                        'default' => $blockStyleDefaults['spacing'],
                    ]
                ],
                'typography'                    => [
                    'defaultFontSizes' => true,
                    'dropCap'          => false,
                    'fontFamilies'     => [
                        'default' => $blockStyleDefaults['font-family']
                    ],
                    'fontSizes'        => [
                        'default' => $blockStyleDefaults['font-size']
                    ],
                    'fontStyle'        => true,
                    'fontWeight'       => true,
                    'letterSpacing'    => true,
                    'textAlign'        => true,
                    'textDecoration'   => true,
                    'textTransform'    => true,
                    'writingMode'      => false,
                    'units'            => ['px'],
                    'fluid'            => false
                ],
                'blocks'                        => [
                    'core/button'    => [
                        'border' => [
                            'radius' => true,
                        ]
                    ],
                    'core/buttons'   => [
                        'border'      => [
                            'radius' => false,
                        ],
                        'spacing'     => [
                            'blockGap' => false,
                        ],
                        'layout'      => false,
                        'contentRole' => false
                    ],
                    'core/image'     => [
                        'lightbox' => [
                            'allowEditing' => true,
                        ]
                    ],
                    'core/pullquote' => [
                        'border' => [
                            'color'  => true,
                            'radius' => true,
                            'style'  => true,
                            'width'  => true,
                        ]
                    ],
                    'core/paragraph' => [
                        'spacing' => [
                            'margin'  => 1,
                            'padding' => 1,
                        ]
                    ],
                    'core/columns'   => [
                        // disable block gap for columns block, but keep for inner column blocks
                        'spacing' => [
                            'blockGap'            => array(
                                '__experimentalDefault' => '20px',
                                'sides'                 => array(
                                    'horizontal'
                                )
                            ),
                            'defaultSpacingSizes' => false,
                        ],
                        'border'  => [
                            'color'  => true,
                            'radius' => false,
                            'style'  => true,
                            'width'  => true,
                        ],
                        'shadow'  => false,
                    ],
                    'core/group'     => [
                        '__experimentalSettings' => false,
                        'shadow'                 => false,
                        'dimensions'             => [
                            'minHeight' => false
                        ],
                        'spacing'                => [
                            'blockGap' => false,
                            'margin'   => true,
                            'padding'  => true,
                        ],
                        'position'               => [
                            'sticky' => false,
                        ],
                        'layout'                 => [
                            'allowSizingOnChildren' => false,
                            'contentSize'           => false
                        ]
                    ],
                    'core/row'       => [
                        '__experimentalSettings' => false,
                        'shadow'                 => false,
                        'dimensions'             => [
                            'minHeight' => false
                        ],
                        'spacing'                => [
                            'blockGap' => true,
                            'margin'   => true,
                            'padding'  => true,
                        ],
                        'position'               => [
                            'sticky' => false,
                        ]
                    ]
                ],
                'layout'                        => [
                    'contentSize' => 'var(--theme-block-max-width)',
                    'wideSize'    => 'var(--theme-block-wide-max-width)',
                ],
                'background'                    => [
                    'backgroundImage' => 1,
                    'backgroundSize'  => 1,
                ],
                'position'                      => [
                    'sticky' => 0,
                ]
            ),
            '__experimentalDiscussionSettings' => [
                'avatarURL'            => 'https://secure.gravatar.com/avatar/?s=96&f=y&r=g',
                'commentOrder'         => 'asc',
                'commentsPerPage'      => '50',
                'defaultCommentsPage'  => 'newest',
                'defaultCommentStatus' => 'open',
                'pageComments'         => '',
                'threadComments'       => '1',
                'threadCommentsDepth'  => '5'
            ],
            '__unstableGalleryWithImageBlocks' => false,
            '__unstableIsBlockBasedTheme'      => false,
            'enableCustomUnits'                => false,
            'fontSizes'                        => [
                [
                    'name' => 'Small',
                    'size' => 'var(--fcom-font-size-small)',
                    'slug' => 'small'
                ],
                [
                    'name' => 'Medium',
                    'size' => 'var(--fcom-font-size-medium)',
                    'slug' => 'medium'
                ],
                [
                    'name' => 'Large',
                    'size' => 'var(--fcom-font-size-large)',
                    'slug' => 'large'
                ],
                [
                    'name' => 'Larger',
                    'size' => 'var(--fcom-font-size-larger)',
                    'slug' => 'larger'
                ],
                [
                    'name' => 'XX-Large',
                    'size' => 'var(--fcom-font-size-xxlarge)',
                    'slug' => 'xxlarge'
                ]
            ],
            'fullscreenMode'                   => 1,
            'enableCustomSpacing'              => 1,
            'enableCustomLineHeight'           => 1,
            'enableCustomFields'               => false,
            'disablePostFormats'               => true,
            'disableLayoutStyles'              => true,
            'disableCustomSpacingSizes'        => false,
            'disableCustomGradients'           => 1,
            'alignWide'                        => true,
            'disableCustomFontSizes'           => false,
            'disableCustomColors'              => false,
            'canUpdateBlockBindings'           => false,
            'bodyPlaceholder'                  => __('Start writing your email...', 'fluent-crm'),
            'allowedBlockTypes'                => $allowedBlocks,
            'gradients'                        => [],
            'imageDefaultSize'                 => 'large',
            'imageEditing'                     => true,
            'isRTL'                            => is_rtl(),
            'autosaveInterval'                 => 999,
            'localAutosaveInterval'            => 999,
            'richEditingEnabled'               => true,
            'spacingSizes'                     => [
                [
                    'name' => '2X-Small',
                    'size' => '0.44rem',
                    'slug' => '20'
                ],
                [
                    'name' => 'X-Small',
                    'size' => '0.67rem',
                    'slug' => '30'
                ],
                [
                    'name' => 'Small',
                    'size' => '1rem',
                    'slug' => '40'
                ],
                [
                    'name' => 'Medium',
                    'size' => '1.5rem',
                    'slug' => '50'
                ],
                [
                    'name' => 'Large',
                    'size' => '2.25rem',
                    'slug' => '60'
                ],
                [
                    'name' => 'X-Large',
                    'size' => '3.38rem',
                    'slug' => '70'
                ],
                [
                    'name' => '2X-Large',
                    'size' => '5.06rem',
                    'slug' => '80'
                ]
            ],
            'titlePlaceholder'                 => __('Add Lesson title', 'fluent-crm')
        );

        $editor_settings['styles'] = $this->getEditorStyleSheets();
        $editor_settings['__unstableResolvedAssets'] = $this->getResolvedAssets();
        $editor_settings['defaultEditorStyles'] = $this->getDefaultEditorStyles();
        $editor_settings['imageSizes'] = $this->getAvailableImageSizes();

        $editor_settings['__experimentalBlockPatterns'] = array_values((array)apply_filters(
            'fluent_crm/block_editor_custom_patterns',
            [],
            $context,
            $requestData
        ));
        $editor_settings['__experimentalBlockPatternCategories'] = array_values((array)apply_filters(
            'fluent_crm/block_editor_custom_pattern_categories',
            [],
            $context,
            $requestData
        ));

        $editor_settings = apply_filters('fluent_crm/block_editor_settings', $editor_settings);
        return $editor_settings;
    }

    /**
     * Return the allowed blocks array for the editor.
     *
     * @return array
     */
    private function getAllowedBlocks()
    {
        $allowedBlocks = [
            'core/block',
            'core/buttons',
            'core/button',
            'core/code',
            'core/columns',
            'core/column',
            'core/footnotes',
            'core/freeform',
            'core/group',
            'core/row',
            'core/heading',
            'core/html',
            'core/image',
            'core/list',
            'core/list-item',
            'core/missing',
            'core/paragraph',
            'core/preformatted',
            'core/pullquote',
            'core/quote',
            'core/rss',
            'core/separator',
            'core/spacer',
            'core/table',
            'core/verse',
            'core/freeform',
            'fluentcrm/conditional-group'
        ];

        if (defined('WC_PLUGIN_FILE')) {
            $allowedBlocks[] = 'fluentcrm/woo-product';
            $allowedBlocks[] = 'fluent-crm/woo-product';
        }

        if (defined('FLUENTCAMPAIGN')) {
            $allowedBlocks[] = 'fluent-crm/latest-posts';
            if (defined('WC_PLUGIN_FILE')) {
                $allowedBlocks[] = 'fluent-crm/woo-products';
            }
        }

        if (defined('FLUENTCART_VERSION')) {
            $allowedBlocks[] = 'fluent-crm/cart-products';
            $allowedBlocks[] = 'fluent-crm/cart-product';
        }

        $aiConfig = $this->getAiWritingConfig();
        if (!empty($aiConfig['enabled'])) {
            $allowedBlocks[] = 'fluent-crm/ai-writer';
        }

        $allowedBlocks = apply_filters('fluent_crm/new_editor_allowed_block_types', $allowedBlocks);
        $allowedBlocks = array_values(array_unique($allowedBlocks));

        return $allowedBlocks;
    }

    /**
     * Return the `styles` array for the editor settings (the massive CSS).
     *
     * @return array
     */
    private function getEditorStyleSheets()
    {
        $defaultPresets = BlockEditorHelper::getStyleDefaultPresets();
        $dynamicCss = BlockEditorHelper::getDynamicCssForEditor();

        return [
            [
                '__unstableType' => 'presets',
                'css'            => ':root{' . $defaultPresets . '--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--theme-palette-color-1: var(--theme-palette-color-1);--wp--preset--color--theme-palette-color-2: var(--theme-palette-color-2);--wp--preset--color--theme-palette-color-3: var(--theme-palette-color-3);--wp--preset--color--theme-palette-color-4: var(--theme-palette-color-4);--wp--preset--color--theme-palette-color-5: var(--theme-palette-color-5);--wp--preset--color--theme-palette-color-6: var(--theme-palette-color-6);--wp--preset--color--theme-palette-color-7: var(--theme-palette-color-7);--wp--preset--color--theme-palette-color-8: var(--theme-palette-color-8);--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--gradient--juicy-peach: linear-gradient(to right, #ffecd2 0%, #fcb69f 100%);--wp--preset--gradient--young-passion: linear-gradient(to right, #ff8177 0%, #ff867a 0%, #ff8c7f 21%, #f99185 52%, #cf556c 78%, #b12a5b 100%);--wp--preset--gradient--true-sunset: linear-gradient(to right, #fa709a 0%, #fee140 100%);--wp--preset--gradient--morpheus-den: linear-gradient(to top, #30cfd0 0%, #330867 100%);--wp--preset--gradient--plum-plate: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--wp--preset--gradient--aqua-splash: linear-gradient(15deg, #13547a 0%, #80d0c7 100%);--wp--preset--gradient--love-kiss: linear-gradient(to top, #ff0844 0%, #ffb199 100%);--wp--preset--gradient--new-retrowave: linear-gradient(to top, #3b41c5 0%, #a981bb 49%, #ffc8a9 100%);--wp--preset--gradient--plum-bath: linear-gradient(to top, #cc208e 0%, #6713d2 100%);--wp--preset--gradient--high-flight: linear-gradient(to right, #0acffe 0%, #495aff 100%);--wp--preset--gradient--teen-party: linear-gradient(-225deg, #FF057C 0%, #8D0B93 50%, #321575 100%);--wp--preset--gradient--fabled-sunset: linear-gradient(-225deg, #231557 0%, #44107A 29%, #FF1361 67%, #FFF800 100%);--wp--preset--gradient--arielle-smile: radial-gradient(circle 248px at center, #16d9e3 0%, #30c7ec 47%, #46aef7 100%);--wp--preset--gradient--itmeo-branding: linear-gradient(180deg, #2af598 0%, #009efd 100%);--wp--preset--gradient--deep-blue: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);--wp--preset--gradient--strong-bliss: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);--wp--preset--gradient--sweet-period: linear-gradient(to top, #3f51b1 0%, #5a55ae 13%, #7b5fac 25%, #8f6aae 38%, #a86aa4 50%, #cc6b8e 62%, #f18271 75%, #f3a469 87%, #f7c978 100%);--wp--preset--gradient--purple-division: linear-gradient(to top, #7028e4 0%, #e5b2ca 100%);--wp--preset--gradient--cold-evening: linear-gradient(to top, #0c3483 0%, #a2b6df 100%, #6b8cce 100%, #a2b6df 100%);--wp--preset--gradient--mountain-rock: linear-gradient(to right, #868f96 0%, #596164 100%);--wp--preset--gradient--desert-hump: linear-gradient(to top, #c79081 0%, #dfa579 100%);--wp--preset--gradient--ethernal-constance: linear-gradient(to top, #09203f 0%, #537895 100%);--wp--preset--gradient--happy-memories: linear-gradient(-60deg, #ff5858 0%, #f09819 100%);--wp--preset--gradient--grown-early: linear-gradient(to top, #0ba360 0%, #3cba92 100%);--wp--preset--gradient--morning-salad: linear-gradient(-225deg, #B7F8DB 0%, #50A7C2 100%);--wp--preset--gradient--night-call: linear-gradient(-225deg, #AC32E4 0%, #7918F2 48%, #4801FF 100%);--wp--preset--gradient--mind-crawl: linear-gradient(-225deg, #473B7B 0%, #3584A7 51%, #30D2BE 100%);--wp--preset--gradient--angel-care: linear-gradient(-225deg, #FFE29F 0%, #FFA99F 48%, #FF719A 100%);--wp--preset--gradient--juicy-cake: linear-gradient(to top, #e14fad 0%, #f9d423 100%);--wp--preset--gradient--rich-metal: linear-gradient(to right, #d7d2cc 0%, #304352 100%);--wp--preset--gradient--mole-hall: linear-gradient(-20deg, #616161 0%, #9bc5c3 100%);--wp--preset--gradient--cloudy-knoxville: linear-gradient(120deg, #fdfbfb 0%, #ebedee 100%);--wp--preset--gradient--soft-grass: linear-gradient(to top, #c1dfc4 0%, #deecdd 100%);--wp--preset--gradient--saint-petersburg: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);--wp--preset--gradient--everlasting-sky: linear-gradient(135deg, #fdfcfb 0%, #e2d1c3 100%);--wp--preset--gradient--kind-steel: linear-gradient(-20deg, #e9defa 0%, #fbfcdb 100%);--wp--preset--gradient--over-sun: linear-gradient(60deg, #abecd6 0%, #fbed96 100%);--wp--preset--gradient--premium-white: linear-gradient(to top, #d5d4d0 0%, #d5d4d0 1%, #eeeeec 31%, #efeeec 75%, #e9e9e7 100%);--wp--preset--gradient--clean-mirror: linear-gradient(45deg, #93a5cf 0%, #e4efe9 100%);--wp--preset--gradient--wild-apple: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);--wp--preset--gradient--snow-again: linear-gradient(to top, #e6e9f0 0%, #eef1f5 100%);--wp--preset--gradient--confident-cloud: linear-gradient(to top, #dad4ec 0%, #dad4ec 1%, #f3e7e9 100%);--wp--preset--gradient--glass-water: linear-gradient(to top, #dfe9f3 0%, white 100%);--wp--preset--gradient--perfect-white: linear-gradient(-225deg, #E3FDF5 0%, #FFE6FA 100%);--wp--preset--font-size--small: var(--fcom-font-size-small);--wp--preset--font-size--medium: var(--fcom-font-size-medium);--wp--preset--font-size--large: var(--fcom-font-size-large);--wp--preset--font-size--x-large: 42px;--wp--preset--font-size--larger: var(--fcom-font-size-larger);--wp--preset--font-size--xxlarge: var(--fcom-font-size-xxlarge);--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}',
                'isGlobalStyles' => true
            ],
            [
                '__unstableType' => 'presets',
                'css'            => '.has-theme-palette-color-1-color{color: var(--wp--preset--color--theme-palette-color-1) !important;}.has-theme-palette-color-2-color{color: var(--wp--preset--color--theme-palette-color-2) !important;}.has-theme-palette-color-3-color{color: var(--wp--preset--color--theme-palette-color-3) !important;}.has-theme-palette-color-4-color{color: var(--wp--preset--color--theme-palette-color-4) !important;}.has-theme-palette-color-5-color{color: var(--wp--preset--color--theme-palette-color-5) !important;}.has-theme-palette-color-6-color{color: var(--wp--preset--color--theme-palette-color-6) !important;}.has-theme-palette-color-7-color{color: var(--wp--preset--color--theme-palette-color-7) !important;}.has-theme-palette-color-8-color{color: var(--wp--preset--color--theme-palette-color-8) !important;}.has-theme-palette-color-1-background-color{background-color: var(--wp--preset--color--theme-palette-color-1) !important;}.has-theme-palette-color-2-background-color{background-color: var(--wp--preset--color--theme-palette-color-2) !important;}.has-theme-palette-color-3-background-color{background-color: var(--wp--preset--color--theme-palette-color-3) !important;}.has-theme-palette-color-4-background-color{background-color: var(--wp--preset--color--theme-palette-color-4) !important;}.has-theme-palette-color-5-background-color{background-color: var(--wp--preset--color--theme-palette-color-5) !important;}.has-theme-palette-color-6-background-color{background-color: var(--wp--preset--color--theme-palette-color-6) !important;}.has-theme-palette-color-7-background-color{background-color: var(--wp--preset--color--theme-palette-color-7) !important;}.has-theme-palette-color-8-background-color{background-color: var(--wp--preset--color--theme-palette-color-8) !important;}.has-theme-palette-color-1-border-color{border-color: var(--wp--preset--color--theme-palette-color-1) !important;}.has-theme-palette-color-2-border-color{border-color: var(--wp--preset--color--theme-palette-color-2) !important;}.has-theme-palette-color-3-border-color{border-color: var(--wp--preset--color--theme-palette-color-3) !important;}.has-theme-palette-color-4-border-color{border-color: var(--wp--preset--color--theme-palette-color-4) !important;}.has-theme-palette-color-5-border-color{border-color: var(--wp--preset--color--theme-palette-color-5) !important;}.has-theme-palette-color-6-border-color{border-color: var(--wp--preset--color--theme-palette-color-6) !important;}.has-theme-palette-color-7-border-color{border-color: var(--wp--preset--color--theme-palette-color-7) !important;}.has-theme-palette-color-8-border-color{border-color: var(--wp--preset--color--theme-palette-color-8) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-juicy-peach-gradient-background{background: var(--wp--preset--gradient--juicy-peach) !important;}.has-young-passion-gradient-background{background: var(--wp--preset--gradient--young-passion) !important;}.has-true-sunset-gradient-background{background: var(--wp--preset--gradient--true-sunset) !important;}.has-morpheus-den-gradient-background{background: var(--wp--preset--gradient--morpheus-den) !important;}.has-plum-plate-gradient-background{background: var(--wp--preset--gradient--plum-plate) !important;}.has-aqua-splash-gradient-background{background: var(--wp--preset--gradient--aqua-splash) !important;}.has-love-kiss-gradient-background{background: var(--wp--preset--gradient--love-kiss) !important;}.has-new-retrowave-gradient-background{background: var(--wp--preset--gradient--new-retrowave) !important;}.has-plum-bath-gradient-background{background: var(--wp--preset--gradient--plum-bath) !important;}.has-high-flight-gradient-background{background: var(--wp--preset--gradient--high-flight) !important;}.has-teen-party-gradient-background{background: var(--wp--preset--gradient--teen-party) !important;}.has-fabled-sunset-gradient-background{background: var(--wp--preset--gradient--fabled-sunset) !important;}.has-arielle-smile-gradient-background{background: var(--wp--preset--gradient--arielle-smile) !important;}.has-itmeo-branding-gradient-background{background: var(--wp--preset--gradient--itmeo-branding) !important;}.has-deep-blue-gradient-background{background: var(--wp--preset--gradient--deep-blue) !important;}.has-strong-bliss-gradient-background{background: var(--wp--preset--gradient--strong-bliss) !important;}.has-sweet-period-gradient-background{background: var(--wp--preset--gradient--sweet-period) !important;}.has-purple-division-gradient-background{background: var(--wp--preset--gradient--purple-division) !important;}.has-cold-evening-gradient-background{background: var(--wp--preset--gradient--cold-evening) !important;}.has-mountain-rock-gradient-background{background: var(--wp--preset--gradient--mountain-rock) !important;}.has-desert-hump-gradient-background{background: var(--wp--preset--gradient--desert-hump) !important;}.has-ethernal-constance-gradient-background{background: var(--wp--preset--gradient--ethernal-constance) !important;}.has-happy-memories-gradient-background{background: var(--wp--preset--gradient--happy-memories) !important;}.has-grown-early-gradient-background{background: var(--wp--preset--gradient--grown-early) !important;}.has-morning-salad-gradient-background{background: var(--wp--preset--gradient--morning-salad) !important;}.has-night-call-gradient-background{background: var(--wp--preset--gradient--night-call) !important;}.has-mind-crawl-gradient-background{background: var(--wp--preset--gradient--mind-crawl) !important;}.has-angel-care-gradient-background{background: var(--wp--preset--gradient--angel-care) !important;}.has-juicy-cake-gradient-background{background: var(--wp--preset--gradient--juicy-cake) !important;}.has-rich-metal-gradient-background{background: var(--wp--preset--gradient--rich-metal) !important;}.has-mole-hall-gradient-background{background: var(--wp--preset--gradient--mole-hall) !important;}.has-cloudy-knoxville-gradient-background{background: var(--wp--preset--gradient--cloudy-knoxville) !important;}.has-soft-grass-gradient-background{background: var(--wp--preset--gradient--soft-grass) !important;}.has-saint-petersburg-gradient-background{background: var(--wp--preset--gradient--saint-petersburg) !important;}.has-everlasting-sky-gradient-background{background: var(--wp--preset--gradient--everlasting-sky) !important;}.has-kind-steel-gradient-background{background: var(--wp--preset--gradient--kind-steel) !important;}.has-over-sun-gradient-background{background: var(--wp--preset--gradient--over-sun) !important;}.has-premium-white-gradient-background{background: var(--wp--preset--gradient--premium-white) !important;}.has-clean-mirror-gradient-background{background: var(--wp--preset--gradient--clean-mirror) !important;}.has-wild-apple-gradient-background{background: var(--wp--preset--gradient--wild-apple) !important;}.has-snow-again-gradient-background{background: var(--wp--preset--gradient--snow-again) !important;}.has-confident-cloud-gradient-background{background: var(--wp--preset--gradient--confident-cloud) !important;}.has-glass-water-gradient-background{background: var(--wp--preset--gradient--glass-water) !important;}.has-perfect-white-gradient-background{background: var(--wp--preset--gradient--perfect-white) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}.has-larger-font-size{font-size: var(--wp--preset--font-size--larger) !important;}.has-xxlarge-font-size{font-size: var(--wp--preset--font-size--xxlarge) !important;}',
                'isGlobalStyles' => true
            ],
            [
                '__unstableType' => 'theme',
                'css'            => ':root { --wp--style--global--content-size: var(--theme-block-max-width);--wp--style--global--wide-size: var(--theme-block-wide-max-width); }:where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: var(--theme-content-spacing); margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: var(--theme-content-spacing); }:root :where(.is-layout-flow) > :first-child{margin-block-start: 0;}:root :where(.is-layout-flow) > :last-child{margin-block-end: 0;}:root :where(.is-layout-flow) > *{margin-block-start: var(--theme-content-spacing);margin-block-end: 0;}:root :where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:root :where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:root :where(.is-layout-constrained) > *{margin-block-start: var(--theme-content-spacing);margin-block-end: 0;}:root :where(.is-layout-flex){gap: var(--theme-content-spacing);}:root :where(.is-layout-grid){gap: var(--theme-content-spacing);}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;}',
                'isGlobalStyles' => true
            ],
            [
                '__unstableType' => 'user',
                'css'            => " :root{--theme-block-max-width: 700px;--global-calc-content-width: 700px;--theme-block-wide-max-width: 820px;--theme-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";--theme-font-weight: 400;--theme-text-transform: none;--theme-text-decoration: none;--theme-font-size: 16px;--theme-line-height: 1.60;--theme-letter-spacing: 0em;--theme-button-font-weight: 500;--theme-button-font-size: 16px;--theme-palette-color-1: #4F46E5;--theme-palette-color-2: #7C3AED;--theme-palette-color-3: #1F2937;--theme-palette-color-4: #374151;--theme-palette-color-5: #6B7280;--theme-palette-color-6: #9CA3AF;--theme-palette-color-7: #E5E7EB;--theme-palette-color-8: #ffffff;--theme-text-color: var(--fcom-primary-text, #19283a);--theme-link-initial-color: var(--theme-palette-color-1);--theme-link-hover-color: var(--theme-palette-color-2);--theme-selection-text-color: #ffffff;--theme-selection-background-color: var(--theme-palette-color-1);--theme-border-color: var(--theme-palette-color-5);--theme-headings-color: var(--theme-palette-color-4);--theme-content-spacing: 1.5em;--theme-button-min-height: 40px;--theme-button-shadow: none;--theme-button-transform: none;--theme-button-text-initial-color: #ffffff;--theme-button-text-hover-color: #ffffff;--theme-button-background-initial-color: var(--theme-palette-color-1);--theme-button-background-hover-color: var(--theme-palette-color-2);--theme-button-border: none;--theme-button-padding: 5px 20px;--theme-normal-container-max-width: 1290px;--theme-content-vertical-spacing: 60px;--theme-container-edge-spacing: 90vw;--theme-narrow-container-max-width: 750px;--theme-wide-offset: 130px;--fcom-font-size-small: 16px;--fcom-font-size-medium: 18px;--fcom-font-size-large: 22px;--fcom-font-size-larger: 26px;--fcom-font-size-xxlarge: 32px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem}body .has-theme-palette-color-1-color{color:var(--theme-palette-color-1)}body .has-theme-palette-color-2-color{color:var(--theme-palette-color-2)}body .has-theme-palette-color-3-color{color:var(--theme-palette-color-3)}body .has-theme-palette-color-4-color{color:var(--theme-palette-color-4)}body .has-theme-palette-color-5-color{color:var(--theme-palette-color-5)}body .has-theme-palette-color-6-color{color:var(--theme-palette-color-6)}body .has-theme-palette-color-7-color{color:var(--theme-palette-color-7)}body .has-theme-palette-color-8-color{color:var(--theme-palette-color-8)}body .has-theme-palette-color-1-background-color{background-color:var(--theme-palette-color-1)}body .has-theme-palette-color-2-background-color{background-color:var(--theme-palette-color-2)}body .has-theme-palette-color-3-background-color{background-color:var(--theme-palette-color-3)}body .has-theme-palette-color-4-background-color{background-color:var(--theme-palette-color-4)}body .has-theme-palette-color-5-background-color{background-color:var(--theme-palette-color-5)}body .has-theme-palette-color-6-background-color{background-color:var(--theme-palette-color-6)}body .has-theme-palette-color-7-background-color{background-color:var(--theme-palette-color-7)}body .has-theme-palette-color-8-background-color{background-color:var(--theme-palette-color-8)}body .has-small-font-size{font-size:var(--fcom-font-size-small)}body .has-medium-font-size{font-size:var(--fcom-font-size-medium)}body .has-large-font-size{font-size:var(--fcom-font-size-large)}body .has-larger-font-size{font-size:var(--fcom-font-size-larger)}body .has-xxlarge-font-size{font-size:var(--fcom-font-size-xxlarge)}body .is-root-container>.alignfull{margin-inline:var(--has-wide, -20px)}body .is-root-container>.wp-block.alignleft{margin-inline-start:calc((100% - min(var(--theme-block-max-width),100%))/2)}body .is-root-container>.wp-block.alignright{margin-inline-end:calc((100% - min(var(--theme-block-max-width),100%))/2)}body :root .wp-element-button{font-family:var(--theme-button-font-family, var(--theme-font-family));font-size:var(--theme-button-font-size);font-weight:var(--theme-button-font-weight);font-style:var(--theme-button-font-style);line-height:var(--theme-button-line-height);letter-spacing:var(--theme-button-letter-spacing);text-transform:var(--theme-button-text-transform);-webkit-text-decoration:var(--theme-button-text-decoration);text-decoration:var(--theme-button-text-decoration)}body :root .wp-block-button[style*=font-weight] .wp-element-button{font-weight:inherit}body .wp-block-columns:last-child{margin-bottom:0}body .has-drop-cap:not(:focus):first-letter{font-size:5.8em;font-weight:700;margin:.1em .12em .05em 0}body figcaption{text-align:center;margin-block:.5em 0}body .wp-block-code,body .wp-block-verse,body .wp-block-preformatted{box-sizing:border-box;tab-size:4;padding:15px 20px;border-radius:3px;background:var(--theme-palette-color-7)}body blockquote{margin-inline:0}body blockquote:where(:not(.is-style-plain)):where(:not(.has-text-align-center):not(.has-text-align-right)){border-inline-start:4px solid var(--theme-palette-color-1)}body blockquote:where(:not(.is-style-plain)).has-text-align-center{padding-block:1.5em;border-block:3px solid var(--theme-palette-color-1)}body blockquote:where(:not(.is-style-plain)).has-text-align-right{border-inline-end:4px solid var(--theme-palette-color-1)}body blockquote:where(:not(.is-style-plain):not(.has-text-align-center):not(.has-text-align-right)){padding-inline-start:1.5em}body blockquote.has-text-align-right{padding-inline-end:1.5em}body blockquote p:last-child{margin-bottom:0}body blockquote cite{font-size:14px}body .wp-block-list{padding-left:30px}body .wp-block-pullquote{position:relative;padding:70px;text-align:initial;border-width:10px;border-style:solid;border-color:var(--theme-palette-color-1)}body .wp-block-pullquote blockquote{border:0;padding:0;margin:0;position:relative;isolation:isolate}body .wp-block-pullquote blockquote p{margin-top:0;margin-bottom:1em}body .wp-block-pullquote blockquote p:last-child{margin-bottom:0}body .wp-block-pullquote blockquote cite{font-size:16px;font-weight:500}body [data-align=left] .wp-block-pullquote,body [data-align=right] .wp-block-pullquote{max-width:50%;margin-top:.3em;margin-bottom:.3em}body .wp-block-table table{border-width:1px}body .wp-block-table table:not(.has-border-color) thead,body .wp-block-table table:not(.has-border-color) tfoot,body .wp-block-table table:not(.has-border-color) td,body .wp-block-table table:not(.has-border-color) th{border-color:var(--theme-table-border-color, var(--theme-border-color))}body .wp-block-table th:not([class*=has-text-align]){text-align:inherit}body .wp-block-table.is-style-stripes{border:0}body .wp-block-button.is-style-outline .wp-element-button{padding:var(--theme-button-padding);border:2px solid;border-color:var(--theme-button-background-initial-color)}body .wp-block-button.is-style-outline .wp-element-button:not(.has-text-color){color:var(--theme-button-background-initial-color)}body .wp-block-button.is-style-outline .wp-element-button:hover{color:var(--theme-button-text-hover-color);border-color:var(--theme-button-background-hover-color);background-color:var(--theme-button-background-hover-color)}body .wp-block-separator{border:none;margin-inline:auto;color:var(--theme-form-field-border-initial-color)}body .wp-block-separator:not(:where(.is-style-wide,.is-style-dots,.alignfull,.alignwide)){max-width:100px !important}body .wp-block-separator:not(.is-style-dots){height:2px;background-color:currentColor}body :root :where(p.has-background,.wp-block-group.has-background){padding:30px;box-sizing:border-box}body h1.has-background,body h2.has-background,body h3.has-background,body h4.has-background,body h5.has-background,body h6.has-background{padding:1.25em 2.375em}body{background-color:var(--fcom-primary-bg, white);background-image:none;font-family:var(--theme-font-family);line-height:var(--theme-line-height)}body .is-root-container{font-size:var(--theme-font-size, 16px);font-family:var(--theme-font-family, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\")}.block-editor-iframe__html.is-zoomed-out .block-editor-iframe__body{padding:20px 30px}.editor-visual-editor__post-title-wrapper.edit-post-visual-editor__post-title-wrapper{margin-top:0px !important;padding-top:0;margin-bottom:30px;position:relative}.editor-visual-editor__post-title-wrapper.edit-post-visual-editor__post-title-wrapper h1{font-size:32px;font-weight:700}h1{--theme-font-weight: 700;--theme-font-size: 40px;--theme-line-height: 1.5}h2{--theme-font-weight: 700;--theme-font-size: 35px;--theme-line-height: 1.5}h3{--theme-font-weight: 700;--theme-font-size: 30px;--theme-line-height: 1.5}h4{--theme-font-weight: 700;--theme-font-size: 25px;--theme-line-height: 1.5}h5{--theme-font-weight: 700;--theme-font-size: 20px;--theme-line-height: 1.5}h6{--theme-font-weight: 700;--theme-font-size: 16px;--theme-line-height: 1.5}.wp-block-pullquote{--theme-font-family: Georgia;--theme-font-weight: 600;--theme-font-size: 25px}pre,code,samp,kbd{--theme-font-family: monospace;--theme-font-weight: 400;--theme-font-size: 16px}figcaption{--theme-font-size: 14px}li::marker{color:#959595}.editor-styles-wrapper{--true: initial;--false: ;--wp--style--global--content-size: var(--theme-block-max-width);--wp--style--global--wide-size: var(--theme-block-wide-max-width);box-sizing:border-box;border:var(--has-boxed, var(--theme-boxed-content-border));padding:var(--has-boxed, var(--theme-boxed-content-spacing));box-shadow:var(--has-boxed, var(--theme-boxed-content-box-shadow));border-radius:var(--has-boxed, var(--theme-boxed-content-border-radius));margin-inline:auto;margin-block:var(--has-boxed, 20px);width:calc(100% - 40px);max-width:100%}:is(.is-layout-flow,.is-layout-constrained)>*:where(:not(h1,h2,h3,h4,h5,h6)){margin-block-start:0;margin-block-end:var(--theme-content-spacing)}:is(.is-layout-flow,.is-layout-constrained) :where(h1,h2,h3,h4,h5,h6){margin-block-end:calc(var(--has-theme-content-spacing, 1)*(.3em + 10px))}:root{color:var(--theme-text-color)}a{color:var(--theme-link-initial-color)}.block-editor-block-list__layout.is-root-container>.alignwide{max-width:var(--theme-block-wide-max-width);box-sizing:border-box}.is-root-container{padding:0 20px}\n"
            ],
            [
                'css'            => file_exists(FLUENTCRM_PLUGIN_PATH . 'assets/guten-editor/index.css')
                    ? file_get_contents(FLUENTCRM_PLUGIN_PATH . 'assets/guten-editor/index.css')
                    : '',
                '__unstableType' => 'user'
            ],
            [
                'css'            => $dynamicCss,
                '__unstableType' => 'user'
            ]
        ];
    }

    /**
     * Return the `__unstableResolvedAssets` for the editor settings.
     *
     * @return array
     */
    private function getResolvedAssets()
    {
        $resolvedStyles = [
            'wp-components-css'           => includes_url('/css/dist/components/style.min.css'),
            'wp-preferences-css'          => includes_url('/css/dist/preferences/style.min.css'),
            'wp-block-editor-css'         => includes_url('/css/dist/block-editor/style.min.css'),
            'wp-reusable-blocks-css'      => includes_url('/css/dist/reusable-blocks/style.min.css'),
            'wp-patterns-css'             => includes_url('/css/dist/patterns/style.min.css'),
            'wp-editor-css'               => includes_url('/css/dist/editor/style.min.css'),
            'wp-block-library-css'        => includes_url('/css/dist/block-library/style.min.css'),
            'wp-block-editor-content-css' => includes_url('/css/dist/block-editor/content.min.css'),
            'wp-edit-blocks-css'          => includes_url('/css/dist/block-library/editor.min.css'),
        ];

        global $wp_version;
        $cssFiles = '';
        foreach ($resolvedStyles as $name => $file) {
            $cssFiles .= "<link rel='stylesheet' id='{$name}' href='{$file}?ver={$wp_version}' media='all' />\n";
        }

        return [
            'scripts' => '<script src="' . includes_url('/js/dist/vendor/wp-polyfill.min.js?ver=3.15.0') . '" id="wp-polyfill-js"></script>',
            'styles'  => $cssFiles
        ];
    }

    /**
     * Return the `defaultEditorStyles` for the editor settings.
     *
     * @return array
     */
    private function getDefaultEditorStyles()
    {
        return [
            [
                'css' => ':root{--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0, 124, 186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0, 107, 161;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0, 90, 135;--wp-admin-border-width-focus:2px;--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122, 0, 223;--wp-bound-block-color:var(--wp-block-synced-color);}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px;}}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:18px;line-height:1.5;--wp--style--block-gap:2em;}p{line-height:1.8;}.editor-post-title__block{font-size:2.5em;font-weight:800;margin-bottom:1em;margin-top:2em;}'
            ]
        ];
    }

    /*
    |--------------------------------------------------------------------------
    | Render: renderPage()
    |--------------------------------------------------------------------------
    */

    protected function renderPage()
    {
        add_action('fluent_crm/new_block_editor_footer', function () {
            wp_underscore_playlist_templates();
            if (function_exists('wp_script_modules') && method_exists(wp_script_modules(), 'print_import_map')) {
                wp_script_modules()->print_import_map();
            }
            wp_print_footer_scripts();
            wp_print_media_templates();
        });

        add_action('fluent_crm_block_editor/head', 'wp_enqueue_scripts', 1);
        add_action('fluent_crm_block_editor/head', 'wp_resource_hints', 2);
        add_action('fluent_crm_block_editor/head', 'wp_preload_resources', 1);
        add_action('fluent_crm_block_editor/head', 'wp_print_styles', 8);
        add_action('fluent_crm_block_editor/head', 'wp_print_head_scripts', 9);

        $this->unloadOtherScripts();
        ?>
        <!DOCTYPE html>
        <html <?php language_attributes(); ?>>
        <head>
            <title>FluentCRM Block Editor</title>
            <meta charset='utf-8'>
            <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover"/>
            <meta name="mobile-web-app-capable" content="yes">
            <meta name="robots" content="noindex">
            <?php do_action('fluent_crm_block_editor/head'); ?>
            <?php do_action('fluent_crm/block_editor_head'); ?>
        </head>
        <body class="fcrm_custom_editor">
        <div class="wp-site-blocks">
            <div id="editor" class="gutenberg__editor"></div>
        </div>
        <?php
        do_action('fluent_crm/new_block_editor_footer');
        ?>
        </body>
        </html>
        <?php
    }

    /*
    |--------------------------------------------------------------------------
    | Isolation: unloadOtherScripts(), buildApprovedSlugsPattern(),
    |            unregisterDefaultBlockPatterns()
    |--------------------------------------------------------------------------
    */

    private function unloadOtherScripts()
    {
        $isSkip = apply_filters('fluent_crm_editor/skip_no_conflict', false);
        if ($isSkip) {
            return;
        }

        $approvedSlugsPattern = $this->buildApprovedSlugsPattern();

        $pluginUrl = str_replace(['http:', 'https:'], '', plugins_url());
        $themesUrl = str_replace(['http:', 'https:'], '', get_theme_root_uri());

        add_filter('script_loader_src', function ($src, $handle) use ($approvedSlugsPattern, $pluginUrl, $themesUrl) {
            if (!$src) {
                return $src;
            }

            if ($this->isThirdPartyAsset($src, $approvedSlugsPattern, $pluginUrl, $themesUrl)) {
                return false;
            }

            return $src;
        }, 1, 2);

        add_filter('style_loader_src', function ($src, $handle) use ($approvedSlugsPattern, $pluginUrl, $themesUrl) {
            if (!$src) {
                return $src;
            }

            if ($this->isThirdPartyAsset($src, $approvedSlugsPattern, $pluginUrl, $themesUrl)) {
                return false;
            }

            return $src;
        }, 1, 2);

        add_action('wp_print_scripts', function () use ($approvedSlugsPattern, $pluginUrl, $themesUrl) {
            global $wp_scripts;
            if (!$wp_scripts) {
                return;
            }

            foreach ($wp_scripts->queue as $script) {
                if (empty($wp_scripts->registered[$script]) || empty($wp_scripts->registered[$script]->src)) {
                    continue;
                }

                $src = $wp_scripts->registered[$script]->src;

                if (!$this->isThirdPartyAsset($src, $approvedSlugsPattern, $pluginUrl, $themesUrl)) {
                    continue;
                }

                wp_dequeue_script($wp_scripts->registered[$script]->handle);
            }
        }, 1);

        add_action('wp_print_styles', function () {
            $isSkip = apply_filters('fluent_crm_editor/skip_no_conflict', false, 'styles');

            if ($isSkip) {
                return;
            }

            // Dequeue theme.json global styles that aren't caught by URL-based filtering
            wp_dequeue_style('global-styles');
            wp_dequeue_style('global-styles-css-custom-properties');

            global $wp_styles;
            if (!$wp_styles) {
                return;
            }

            $approvedSlugs = apply_filters('fluent_crm_editor/asset_listed_slugs', [
                '\/gutenberg\/',
            ]);

            $approvedSlugs[] = '\/fluent-crm\/';

            $approvedSlugs = array_unique($approvedSlugs);
            $approvedSlugs = implode('|', $approvedSlugs);

            $pluginUrl = plugins_url();
            $themeUrl = get_theme_root_uri();

            $pluginUrl = str_replace(['http:', 'https:'], '', $pluginUrl);
            $themeUrl = str_replace(['http:', 'https:'], '', $themeUrl);

            foreach ($wp_styles->queue as $script) {

                if (empty($wp_styles->registered[$script]) || empty($wp_styles->registered[$script]->src)) {
                    continue;
                }

                $src = $wp_styles->registered[$script]->src;
                $pluginMatched = (strpos($src, $pluginUrl) !== false) && !preg_match('/' . $approvedSlugs . '/', $src);
                $themeMatched = (strpos($src, $themeUrl) !== false) && !preg_match('/' . $approvedSlugs . '/', $src);

                if (!$pluginMatched && !$themeMatched) {
                    continue;
                }

                wp_dequeue_style($wp_styles->registered[$script]->handle);
            }
        }, 999999);
    }

    /**
     * Build the regex pattern string from approved asset slugs.
     *
     * @return string
     */
    private function buildApprovedSlugsPattern()
    {
        /**
         * Define the list of approved slugs for FluentCRM assets.
         *
         * This filter allows modification of the list of slugs that are approved for FluentCRM assets.
         *
         * @param array $approvedSlugs An array of approved slugs for FluentCRM assets.
         */
        $approvedSlugs = apply_filters('fluent_crm_editor/asset_listed_slugs', [
            '\/gutenberg\/',
        ]);
        $approvedSlugs[] = 'fluent-crm';
        $approvedSlugs = array_unique($approvedSlugs);

        return implode('|', $approvedSlugs);
    }

    /**
     * Check if an asset src is a third-party plugin/theme asset that should be blocked.
     *
     * @param string $src
     * @param string $pattern
     * @param string $pluginUrl
     * @param string $themesUrl
     * @return bool
     */
    private function isThirdPartyAsset($src, $pattern, $pluginUrl, $themesUrl)
    {
        $pluginMatched = (strpos($src, $pluginUrl) !== false) && !preg_match('/' . $pattern . '/', $src);
        if ($pluginMatched) {
            return true;
        }

        $themeMatched = (strpos($src, $themesUrl) !== false) && !preg_match('/' . $pattern . '/', $src);
        if ($themeMatched) {
            return true;
        }

        return false;
    }

    protected function unregisterDefaultBlockPatterns($context = '', $data = [])
    {
        // Only affect FluentCRM iframe editor requests, never global wp-admin editors.
        if (!isset($_REQUEST['fluent_crm_block_editor'])) {
            return;
        }

        $shouldUnregister = (bool)apply_filters('fluent_crm/block_editor_unregister_all_patterns', true, $context, $data);
        if (!$shouldUnregister) {
            return;
        }

        // Prevent late core/theme pattern registration hooks from repopulating defaults.
        foreach ([
            '_register_core_block_patterns_and_categories',
            '_register_theme_block_patterns',
            '_register_remote_theme_patterns'
        ] as $callback) {
            remove_action('init', $callback, 9);
            remove_action('init', $callback, 10);
        }

        add_filter('should_load_remote_block_patterns', '__return_false', 999);
        remove_theme_support('core-block-patterns');

        if (class_exists('\WP_Block_Patterns_Registry')) {
            $registry = \WP_Block_Patterns_Registry::get_instance();
            $patterns = method_exists($registry, 'get_all_registered') ? $registry->get_all_registered() : [];
            foreach (array_keys($patterns) as $patternName) {
                if (method_exists($registry, 'unregister')) {
                    $registry->is_registered($patternName) && $registry->unregister($patternName);
                }
            }
        }

        if (class_exists('\WP_Block_Pattern_Categories_Registry')) {
            $categoryRegistry = \WP_Block_Pattern_Categories_Registry::get_instance();
            $categories = method_exists($categoryRegistry, 'get_all_registered') ? $categoryRegistry->get_all_registered() : [];
            foreach (array_keys($categories) as $categoryName) {
                if (method_exists($categoryRegistry, 'unregister')) {
                    $categoryRegistry->is_registered($categoryName) && $categoryRegistry->unregister($categoryName);
                }
            }
        }
    }

    /*
    |--------------------------------------------------------------------------
    | Helpers: getRequiredCapability(), parseBoolParam(), getAvailableImageSizes()
    |--------------------------------------------------------------------------
    */

    /**
     * Map a block type to the required FluentCRM capability.
     *
     * @param string $blockType
     * @return string
     */
    private static function getRequiredCapability($blockType)
    {
        if (in_array($blockType, ['campaign', 'email_body_in_funnel', 'recurring_campaign', 'recurring_mail', 'sequence_mail'], true)) {
            return 'fcrm_manage_emails';
        }
        if ($blockType === 'template') {
            return 'fcrm_manage_email_templates';
        }
        return 'fcrm_read_emails';
    }

    /**
     * Parse a loosely-typed boolean parameter from a request value.
     *
     * @param mixed $value
     * @return bool
     */
    private static function parseBoolParam($value)
    {
        if (is_bool($value)) {
            return $value;
        }
        if (is_numeric($value)) {
            return ((int)$value) === 1;
        }
        $value = strtolower(trim((string)$value));
        if ($value === '1' || $value === 'true' || $value === 'yes' || $value === 'on') {
            return true;
        }
        if ($value === '0' || $value === 'false' || $value === 'no' || $value === 'off') {
            return false;
        }
        return false;
    }

    /**
     * Get available image sizes for the editor.
     *
     * @return array
     */
    private function getAvailableImageSizes()
    {
        $size_names = apply_filters(
            'image_size_names_choose',
            array(
                'thumbnail' => __('Thumbnail', 'fluent-crm'),
                'medium'    => __('Medium', 'fluent-crm'),
                'large'     => __('Large', 'fluent-crm'),
                'full'      => __('Full Size', 'fluent-crm'),
            )
        );
        $all_sizes = array();
        foreach ($size_names as $size_slug => $size_name) {
            $all_sizes[] = array(
                'slug' => $size_slug,
                'name' => $size_name,
            );
        }
        return $all_sizes;
    }
}
