<?php
/**
 * Plugin Name:       SmartCloud AI-Kit – On-Device AI Tools
 * Plugin URI:        https://wpsuite.io/ai-kit/
 * Description:       Bring on-device, zero-cost AI directly into WordPress. Create, rewrite, translate, proofread, summarize, and SEO-optimize content using Chrome's built-in AI — no API keys, no cloud, no tokens, no data leaving the browser.
 * Requires at least: 6.2
 * Tested up to:      7.0
 * Requires PHP:      8.1
 * Version:           1.4.4
 * Author:            Smart Cloud Solutions Inc.
 * Author URI:        https://smart-cloud-solutions.com
 * License:           MIT
 * License URI:       https://mit-license.org/
 * Text Domain:       smartcloud-ai-kit
 *
 * @package           smartcloud-ai-kit
 */

namespace SmartCloud\WPSuite\AiKit;

const VERSION = '1.4.4';
const DB_VERSION = '1.3.1';

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

if (version_compare(PHP_VERSION, '8.1', '<')) {
    deactivate_plugins(plugin_basename(__FILE__));
    wp_die(
        esc_html__('AI-Kit requires PHP 8.1 or higher.', 'smartcloud-ai-kit'),
        esc_html__('Plugin dependency check', 'smartcloud-ai-kit'),
        array('back_link' => true)
    );
}

/**
 * Main plugin class.
 */
final class AiKit
{

    /** Singleton instance */
    private static ?AiKit $instance = null;

    /** Admin instance */
    private Admin $admin;

    /** KB Admin instance */
    private KnowledgeBase\Admin $kbAdmin;

    private function __construct()
    {
        $this->defineConstants();
        $this->includes();
    }

    /** @var string[] */
    private array $blocks = [
        'ai-feature',
        'doc-search',
        'kb-section',
    ];

    /**
     * Access the singleton instance.
     */
    public static function instance(): AiKit
    {
        return self::$instance ?? (self::$instance = new self());
    }

    /**
     * Get KB Admin instance
     */
    public function getKbAdmin(): KnowledgeBase\Admin
    {
        return $this->kbAdmin;
    }

    /**
     * Define required constants.
     */
    /**
     * Init callback – registers blocks.
     */
    public function init(): void
    {
        add_filter('block_bindings_supported_attributes', array($this, 'filterBlockBindingsSupportedAttributes'), 20, 2);
        add_filter('block_bindings_supported_attributes_smartcloud-ai-kit/feature', array($this, 'filterAiFeatureBlockBindingsSupportedAttributes'), 20, 1);
        add_filter('block_bindings_supported_attributes_smartcloud-ai-kit/doc-search', array($this, 'filterDocSearchBlockBindingsSupportedAttributes'), 20, 1);

        add_action('add_meta_boxes', array($this, 'registerAttachmentMetabox'), 10);
        add_filter('bulk_actions-upload', array($this, 'registerMediaBulkActions'), 10, 1);
        add_filter('handle_bulk_actions-upload', array($this, 'handleMediaBulkAction'), 10, 3);

        $this->registerBlocks();

        // Assets
        add_action('wp_head', array($this, 'addMainScript'), 1);
        add_action('admin_head', array($this, 'addMainScript'), 1);

        add_action('wp_enqueue_scripts', array($this, 'enqueueFrontendAssets'), 20);
        add_action('elementor/preview/after_enqueue_scripts', array($this, 'enqueueFrontendAssets'), 20);

        add_action('enqueue_block_editor_assets', array($this, 'enqueueEditorAssets'), 20);
        add_filter('block_categories_all', array($this, 'registerBlockCategory'), 20, 2);
        add_action('admin_enqueue_scripts', array($this, 'enqueueAdminAssets'), 20);

        add_action('admin_menu', array($this, 'createAdminMenu'), 20);

        // KB Admin hooks
        if ($this->kbAdmin) {
            $this->kbAdmin->registerHooks();
        }

        // Shortcodes
        add_shortcode('smartcloud-ai-kit-feature', array($this, 'shortcodeFeature'));
        add_shortcode('smartcloud-ai-kit-doc-search', array($this, 'shortcodeDocSearch'));

        add_filter('no_texturize_shortcodes', function ($shortcodes) {
            $shortcodes[] = 'smartcloud-ai-kit-feature';
            $shortcodes[] = 'smartcloud-ai-kit-doc-search';
            return $shortcodes;
        });
    }

    public function registerAttachmentMetabox()
    {
        add_meta_box(
            'ai_kit_generate_metadata',
            __('Generate SEO metadata', 'smartcloud-ai-kit'),
            function ($post) {
                if (!($post instanceof \WP_Post) || $post->post_type !== 'attachment') {
                    return;
                }
                echo '<div id="smartcloud-ai-kit-attachment-metabox-root" data-attachment-id="' . esc_attr((string) $post->ID) . '"></div>';
            },
            'attachment',
            'side',
            'high'
        );
    }

    public function registerMediaBulkActions($actions)
    {
        $actions['smartcloud-ai-kit-preview-ai-metadata'] = __('Preview SEO metadata', 'smartcloud-ai-kit');
        return $actions;
    }

    public function handleMediaBulkAction($redirect_to, $doaction, $post_ids)
    {
        if ($doaction !== 'smartcloud-ai-kit-preview-ai-metadata') {
            return $redirect_to;
        }

        if (!current_user_can('upload_files')) {
            return $redirect_to;
        }

        if (
            empty($_REQUEST['_wpnonce']) ||
            !wp_verify_nonce(
                sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])),
                'bulk-media'
            )
        ) {
            return $redirect_to;
        }

        $ids = [];
        if (!empty($_REQUEST['media']) && is_array($_REQUEST['media'])) {
            $ids = array_map('absint', wp_unslash($_REQUEST['media']));
        } elseif (!empty($post_ids) && is_array($post_ids)) {
            $ids = array_map('absint', $post_ids);
        }

        $ids = array_values(array_filter($ids, fn($n) => $n > 0));

        $ids = array_values(array_filter($ids, fn($id) => current_user_can('edit_post', $id)));

        if (!$ids) {
            return $redirect_to;
        }

        return add_query_arg([
            'ai_kit_preview' => 1,
            'ai_kit_ids' => implode(',', $ids),
        ], $redirect_to);
    }
    /**
     * Include admin classes or additional files.
     */
    public function registerWidgets(): void
    {
        // Elementor KB Section Widget
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'elementor-kb-section-widget.php')) {
            add_action('elementor/init', static function () {
                require_once SMARTCLOUD_AI_KIT_PATH . 'elementor-kb-section-widget.php';
            });
        }

        // Elementor AI-Kit Widgets (Feature, Doc Search)
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'elementor-ai-kit-widgets.php')) {
            add_action('elementor/init', static function () {
                require_once SMARTCLOUD_AI_KIT_PATH . 'elementor-ai-kit-widgets.php';
            });
        }
    }

    /**
     * Register custom block category.
     */
    public function registerBlockCategory(array $categories, \WP_Block_Editor_Context $context): array
    {
        $categories[] = array(
            'slug' => 'smartcloud-ai-kit',
            'title' => __('SmartCloud - AI-Kit', 'smartcloud-ai-kit'),
            'icon' => null,
        );
        return $categories;
    }

    public function registerBlocks(): void
    {
        if (!function_exists('register_block_type')) {
            return;
        }

        foreach ($this->blocks as $block) {
            $metadata_path = SMARTCLOUD_AI_KIT_PATH . 'blocks/' . $block;
            if (file_exists($metadata_path . '/block.json')) {
                register_block_type($metadata_path);
            }
        }
    }

    public function filterAiFeatureBlockBindingsSupportedAttributes(array $supported_attributes): array
    {
        return array_values(array_unique(array_merge($supported_attributes, $this->getAiFeatureBindableAttributes())));
    }

    public function filterDocSearchBlockBindingsSupportedAttributes(array $supported_attributes): array
    {
        return array_values(array_unique(array_merge($supported_attributes, $this->getDocSearchBindableAttributes())));
    }

    public function filterBlockBindingsSupportedAttributes(array $supported_attributes, ?string $block_type_name = null): array
    {
        if ($block_type_name === 'smartcloud-ai-kit/feature') {
            return $this->filterAiFeatureBlockBindingsSupportedAttributes($supported_attributes);
        }

        if ($block_type_name === 'smartcloud-ai-kit/doc-search') {
            return $this->filterDocSearchBlockBindingsSupportedAttributes($supported_attributes);
        }

        return $supported_attributes;
    }

    private function getAiFeatureBindableAttributes(): array
    {
        return array(
            'style',
            'mode',
            'editable',
            'autoRun',
            'onDeviceTimeout',
            'default',
            'allowOverride',
            'optionsDisplay',
            'inputSelector',
            'outputSelector',
            'variation',
            'title',
            'openButtonTitle',
            'openButtonIcon',
            'showOpenButtonTitle',
            'showOpenButtonIcon',
            'showRegenerateOnBackendButton',
            'acceptButtonTitle',
            'language',
            'direction',
            'colorMode',
            'primaryColor',
            'primaryShade',
            'colors',
            'themeOverrides',
        );
    }

    private function getDocSearchBindableAttributes(): array
    {
        return array(
            'variation',
            'autoRun',
            'enableUserFilters',
            'title',
            'inputSelector',
            'showOpenButton',
            'openButtonTitle',
            'showOpenButtonTitle',
            'openButtonIcon',
            'showOpenButtonIcon',
            'searchButtonIcon',
            'showSearchButtonTitle',
            'showSearchButtonIcon',
            'language',
            'direction',
            'colorMode',
            'primaryColor',
            'themeOverrides',
            'topK',
            'snippetMaxChars',
        );
    }

    private function getWpsuiteThemeCssHref(): ?string
    {
        if (!defined('SMARTCLOUD_WPSUITE_SLUG')) {
            return null;
        }

        $upload_dir_info = wp_upload_dir();
        $css_path = trailingslashit($upload_dir_info['basedir']) . SMARTCLOUD_WPSUITE_SLUG . '/wpsuite-theme.css';

        if (!file_exists($css_path)) {
            return null;
        }

        $css_url = trailingslashit($upload_dir_info['baseurl']) . SMARTCLOUD_WPSUITE_SLUG . '/wpsuite-theme.css';
        $version = filemtime($css_path) ?: SMARTCLOUD_AI_KIT_VERSION;

        return add_query_arg('ver', (string) $version, $css_url);
    }

    /**
     * Enqueue inline scripts that expose PHP constants to JS.
     */
    private function enqueueMainRuntimeScript(): void
    {
        $main_script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'main/index.asset.php')) {
            $main_script_asset = require(SMARTCLOUD_AI_KIT_PATH . 'main/index.asset.php');
        }
        $main_script_dependencies = array_merge(
            $main_script_asset['dependencies'] ?? array(),
            array('smartcloud-wpsuite-webcrypto-vendor', 'smartcloud-wpsuite-amplify-vendor', 'smartcloud-wpsuite-mantine-vendor')
        );
        if (wp_script_is('smartcloud-wpsuite-main-script', 'registered')) {
            $main_script_dependencies[] = 'smartcloud-wpsuite-main-script';
        }
        $main_script_asset['dependencies'] = array_values(array_unique($main_script_dependencies));
        wp_enqueue_script('smartcloud-ai-kit-main-script', SMARTCLOUD_AI_KIT_URL . 'main/index.js', $main_script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));
        //wp_enqueue_style('smartcloud-ai-kit-main-style', SMARTCLOUD_AI_KIT_URL . 'main/index.css', array(), SMARTCLOUD_AI_KIT_VERSION);
        //add_editor_style(SMARTCLOUD_AI_KIT_URL . 'main/index.css');
    }

    private function enqueueFormViewAssets(): void
    {
        $view_script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'blocks/view.asset.php')) {
            $view_script_asset = require(SMARTCLOUD_AI_KIT_PATH . 'blocks/view.asset.php');
        }
        $view_script_dependencies = array_merge(
            $view_script_asset['dependencies'] ?? array(),
            array('smartcloud-ai-kit-main-script')
        );
        if (wp_script_is('smartcloud-wpsuite-main-script', 'registered')) {
            $view_script_dependencies[] = 'smartcloud-wpsuite-main-script';
        }
        $view_script_asset['dependencies'] = array_values(array_unique($view_script_dependencies));
        wp_enqueue_script('smartcloud-ai-kit-view-script', SMARTCLOUD_AI_KIT_URL . 'blocks/view.js', $view_script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));
    }

    /**
     * Add inline scripts that expose PHP constants to JS.
     */
    public function addMainScript(): void
    {
        // Build data passed to JS.
        $settings = $this->admin->getSettings();
        $data = array(
            'key' => SMARTCLOUD_AI_KIT_SLUG,
            'version' => SMARTCLOUD_AI_KIT_VERSION,
            'status' => 'initializing',
            'plugin' => array(),
            'settings' => $settings,
            'restUrl' => rest_url(SMARTCLOUD_AI_KIT_SLUG . '/v1'),
            'nonce' => wp_create_nonce('wp_rest'),
        );
        $constants = array(
            'mantineCssHref' => add_query_arg(
                'ver',
                \SmartCloud\WPSuite\Hub\VERSION_MANTINE,
                SMARTCLOUD_WPSUITE_URL . 'assets/css/mantine-vendor.css'
            ),
            'aiKitUiCssHref' => add_query_arg(
                'ver',
                SMARTCLOUD_AI_KIT_VERSION,
                SMARTCLOUD_AI_KIT_URL . 'main/index.css'
            ),
            'wpsuiteThemeCssHref' => $this->getWpsuiteThemeCssHref(),
        );

        $js = 'const __aikitGlobal = (typeof globalThis !== "undefined") ? globalThis : window;
    __aikitGlobal.WpSuite = __aikitGlobal.WpSuite ?? {};
    __aikitGlobal.WpSuite.plugins = __aikitGlobal.WpSuite.plugins ?? {};
    __aikitGlobal.WpSuite.events = __aikitGlobal.WpSuite.events ?? {
      emit: function (type, detail) { window.dispatchEvent(new CustomEvent(type, { detail })); },
      on: function (type, cb, opts) { window.addEventListener(type, cb, opts); },
    };
    __aikitGlobal.WpSuite.plugins.aiKit = __aikitGlobal.WpSuite.plugins.aiKit ?? {};
Object.assign(__aikitGlobal.WpSuite.plugins.aiKit, ' . wp_json_encode($data) . ');
__aikitGlobal.WpSuite.constants = __aikitGlobal.WpSuite.constants ?? {};
__aikitGlobal.WpSuite.constants.aiKit = ' . wp_json_encode($constants) . ';
var WpSuite = __aikitGlobal.WpSuite;
';
        wp_print_inline_script_tag(wp_kses_post($js));
    }

    public function enqueueFrontendAssets(): void
    {
        $this->enqueueMainRuntimeScript();
        $this->enqueueFormViewAssets();
    }

    public function enqueueAdminRuntimeAssets(): void
    {
        $this->enqueueMainRuntimeScript();
    }

    public function enqueueEditorAssets(): void
    {
        $this->enqueueMainRuntimeScript();
        $this->registerEditorRuntimeAssets();

        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'blocks/editor.css')) {
            wp_enqueue_style(
                'smartcloud-ai-kit-blocks-editor-style',
                SMARTCLOUD_AI_KIT_URL . 'blocks/editor.css',
                array(),
                SMARTCLOUD_AI_KIT_VERSION
            );
        }
    }

    public function enqueueAdminAssets($hook): void
    {
        if ($hook !== 'upload.php' && $hook !== 'post.php') {
            return;
        }

        // post.php-n csak attachmentnél:
        if ($hook === 'post.php') {
            $screen = function_exists('get_current_screen') ? get_current_screen() : null;
            if (!$screen || $screen->id !== 'attachment')
                return;
        }

        $this->enqueueAdminRuntimeAssets();

        $script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'admin/media.asset.php')) {
            $script_asset = require_once(SMARTCLOUD_AI_KIT_PATH . 'admin/media.asset.php');
        }
        $script_asset['dependencies'] = array_merge($script_asset['dependencies'], array('smartcloud-ai-kit-main-script'));
        wp_enqueue_script('smartcloud-ai-kit-media-script', SMARTCLOUD_AI_KIT_URL . 'admin/media.js', $script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));
    }

    /**
     * Enqueue inline editor scripts that expose PHP constants to JS.
     */
    private function registerEditorRuntimeAssets(): void
    {
        $blocks_script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'blocks/editor.asset.php')) {
            $blocks_script_asset = require(SMARTCLOUD_AI_KIT_PATH . 'blocks/editor.asset.php');
        }
        $blocks_script_asset['dependencies'] = array_merge($blocks_script_asset['dependencies'], array('smartcloud-ai-kit-main-script'));
        wp_enqueue_script('smartcloud-ai-kit-blocks-editor-script', SMARTCLOUD_AI_KIT_URL . 'blocks/editor.js', $blocks_script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));
        wp_enqueue_style('smartcloud-ai-kit-blocks-editor-style', SMARTCLOUD_AI_KIT_URL . 'blocks/editor.css', array(), SMARTCLOUD_AI_KIT_VERSION);
        add_editor_style(SMARTCLOUD_AI_KIT_URL . 'blocks/editor.css');

        $script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'admin/media.asset.php')) {
            $script_asset = require_once(SMARTCLOUD_AI_KIT_PATH . 'admin/media.asset.php');
        }
        $script_asset['dependencies'] = array_merge($script_asset['dependencies'], array('smartcloud-ai-kit-main-script'));
        wp_enqueue_script('smartcloud-ai-kit-media-script', SMARTCLOUD_AI_KIT_URL . 'admin/media.js', $script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));
        $script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'admin/sidebar.asset.php')) {
            $script_asset = require_once(SMARTCLOUD_AI_KIT_PATH . 'admin/sidebar.asset.php');
        }
        $script_asset['dependencies'] = array_merge($script_asset['dependencies'], array('smartcloud-ai-kit-main-script'));
        wp_enqueue_script('smartcloud-ai-kit-sidebar-script', SMARTCLOUD_AI_KIT_URL . 'admin/sidebar.js', $script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));

        $script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'admin/langutils.asset.php')) {
            $script_asset = require_once(SMARTCLOUD_AI_KIT_PATH . 'admin/langutils.asset.php');
        }
        $script_asset['dependencies'] = array_merge($script_asset['dependencies'], array('smartcloud-ai-kit-main-script'));
        wp_enqueue_script('smartcloud-ai-kit-langutils-script', SMARTCLOUD_AI_KIT_URL . 'admin/langutils.js', $script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));

        $script_asset = array();
        if (file_exists(filename: SMARTCLOUD_AI_KIT_PATH . 'admin/imgextra.asset.php')) {
            $script_asset = require_once(SMARTCLOUD_AI_KIT_PATH . 'admin/imgextra.asset.php');
        }
        $script_asset['dependencies'] = array_merge($script_asset['dependencies'], array('smartcloud-ai-kit-main-script'));
        wp_enqueue_script('smartcloud-ai-kit-imgextra-script', SMARTCLOUD_AI_KIT_URL . 'admin/imgextra.js', $script_asset['dependencies'], SMARTCLOUD_AI_KIT_VERSION, array('in_footer' => true, 'strategy' => 'defer'));
    }

    /**
     * Shortcode handler for [smartcloud-ai-kit-feature]
     */

    /**
     * Shared shortcode parsing/normalization for AI-Kit blocks.
     *
     * - Supports camelCase, kebab-case and snake_case attribute names.
     * - Merges defaults + (optional) surrounding block attrs + shortcode attrs.
     * - Decodes selected JSON-ish attributes when provided as strings.
     * - Supports "mini-YAML" shortcode body via configB64 + configFormat.
     *
     * @param array  $atts
     * @param mixed  $content
     * @param array  $attribute_defaults
     * @param array  $json_attrs
     * @return array{0: array, 1: bool} [attrs, is_preview]
     */
    private function buildShortcodeBlockAttrs($atts, $content, array $attribute_defaults, array $json_attrs = array()): array
    {
        global $block;

        $provided_atts = array_change_key_case((array) $atts, CASE_LOWER);

        $block_attrs = array();
        if (is_array($block) && isset($block['attrs']) && is_array($block['attrs'])) {
            $block_attrs = $block['attrs'];
        }

        $is_preview = is_admin();
        if (!$is_preview && did_action('elementor/loaded') && class_exists('\\Elementor\\Plugin')) {
            $plugin = \Elementor\Plugin::$instance;
            if (isset($plugin->preview) && method_exists($plugin->preview, 'is_preview_mode')) {
                $is_preview = $plugin->preview->is_preview_mode();
            }
        }

        $attrs = array();
        foreach ($attribute_defaults as $attr_name => $default_value) {
            // Support camelCase / kebab-case / snake_case variants for shortcodes
            $slugged = preg_replace('/([a-z])([A-Z])/', '$1-$2', $attr_name);
            $shortcode_keys = array_unique(
                array(
                    strtolower($attr_name),
                    strtolower(str_replace('-', '_', $slugged)),
                    strtolower($slugged),
                )
            );

            $has_shortcode_value = false;
            $shortcode_value = null;
            foreach ($shortcode_keys as $candidate_key) {
                if (array_key_exists($candidate_key, $provided_atts)) {
                    $shortcode_value = $provided_atts[$candidate_key];
                    $has_shortcode_value = true;
                    break;
                }
            }

            $block_value = array_key_exists($attr_name, $block_attrs) ? $block_attrs[$attr_name] : null;
            $value = $has_shortcode_value ? $shortcode_value : ($block_value ?? $default_value);

            // Decode JSON-like attributes if provided as a string in the shortcode
            if (is_string($value)) {
                $trimmed = trim($value);
                if ($trimmed !== '' && in_array($attr_name, $json_attrs, true)) {
                    $decoded = json_decode($value, true);
                    if (json_last_error() === JSON_ERROR_NONE) {
                        $value = $decoded;
                    }
                }
            }

            if (in_array($attr_name, $json_attrs, true) && is_object($value)) {
                $value = json_decode(wp_json_encode($value), true);
            }

            // Special-case: allowOverride can contain booleans encoded as strings/numbers
            if ($attr_name === 'allowOverride' && is_array($value)) {
                foreach ($value as $allow_key => $allow_value) {
                    if (is_string($allow_value)) {
                        $lower = strtolower($allow_value);
                        if (in_array($lower, array('true', '1', 'yes'), true)) {
                            $value[$allow_key] = true;
                        } elseif (in_array($lower, array('false', '0', 'no'), true)) {
                            $value[$allow_key] = false;
                        }
                    } elseif (is_numeric($allow_value)) {
                        $value[$allow_key] = ((int) $allow_value) === 1;
                    }
                }
            }

            // Back-compat: accept { name, color } form for the single-color "colors" map
            if ($attr_name === 'colors' && is_array($value) && isset($value['name'], $value['color']) && count($value) === 2) {
                $value = array(
                    $value['name'] => $value['color'],
                );
            }

            $attrs[$attr_name] = $value;
        }

        // Content-based config (human friendly mini-YAML)
        $normalized_content = $this->normalize_shortcode_content($content);
        if (is_string($normalized_content) && trim($normalized_content) !== '') {
            // base64 (standard, not url-safe)
            $attrs['configB64'] = base64_encode($normalized_content);

            // optional: versioning to allow changing format later
            $attrs['configFormat'] = 'yaml.v1';
        }

        return array($attrs, $is_preview);
    }

    /**
     * Render a dynamic AI-Kit block from a shortcode.
     *
     * @param string $block_name
     * @param array  $attrs
     * @param bool   $is_preview
     * @return string
     */
    private function renderShortcodeBlock(string $block_name, array $attrs, bool $is_preview): string
    {
        $newBlock = array(
            'blockName' => $block_name,
            'attrs' => $attrs,
        );

        $content = render_block($newBlock);
        $content = str_replace("smartcloud-ai-kit-is-preview", ($is_preview ? 'true' : 'false'), $content);
        return $content;
    }

    public function shortcodeFeature($atts = array(), $content = null): string
    {

        $attribute_defaults = array(
            'mode' => null,
            'editable' => false,
            'autoRun' => null,
            'onDeviceTimeout' => null,
            'default' => null,
            'allowOverride' => null,
            'optionsDisplay' => null,
            'inputSelector' => null,
            'outputSelector' => null,
            'variation' => 'default',
            'title' => null,
            'openButtonTitle' => null,
            'showOpenButtonTitle' => null,
            'openButtonIcon' => null,
            'showOpenButtonIcon' => null,
            'showRegenerateOnBackendButton' => null,
            'acceptButtonTitle' => null,
            'language' => 'system',
            'direction' => 'auto',
            'colorMode' => 'light',
            'primaryColor' => null,
            'primaryShade' => null,
            'colors' => null,
            'uid' => strtolower(\function_exists('wp_generate_password') ? \wp_generate_password(8, false, false) : substr(md5(uniqid('', true)), 0, 8)),
            'themeOverrides' => null,
        );

        list($attrs, $is_preview) = $this->buildShortcodeBlockAttrs(
            $atts,
            $content,
            $attribute_defaults,
            array('allowOverride', 'default', 'colors', 'primaryShade', 'themeOverrides')
        );

        return $this->renderShortcodeBlock('smartcloud-ai-kit/feature', $attrs, $is_preview);
    }



    /**
     * Shortcode handler for [smartcloud-ai-kit-doc-search]
     *
     * Mirrors the DocSearch (KB research) block rendering so it can be used
     * in classic editors / page builders (e.g. Elementor) the same way as the feature shortcode.
     *
     * Supported attributes (shortcode keys are case-insensitive; kebab_case / snake_case variants also work):
     * - variation (default: "default")
     * - title
     * - showOpenButton
     * - openButtonTitle
     * - showOpenButtonTitle
     * - openButtonIcon
     * - showOpenButtonIcon
     * - showSearchButtonTitle
     * - searchButtonIcon (base64-encoded image data URI)
     * - showSearchButtonIcon
     * - language (default: "system")
     * - direction (default: "auto")
     * - colorMode (default: "light")
     * - primaryColor
     * - themeOverrides
     * - topK
     * - snippetMaxChars
     *
     * Optional content: mini-YAML (same as the blocks) which will be passed as configB64.
     */
    public function shortcodeDocSearch($atts = array(), $content = null): string
    {

        $attribute_defaults = array(
            'inputSelector' => null,
            'variation' => 'default',
            'autoRun' => null,
            'enableUserFilters' => null,
            'title' => null,
            'showOpenButton' => null,
            'openButtonTitle' => null,
            'showOpenButtonTitle' => null,
            'openButtonIcon' => null,
            'showOpenButtonIcon' => null,
            'showSearchButtonTitle' => null,
            'searchButtonIcon' => null,
            'showSearchButtonIcon' => null,
            'language' => 'system',
            'direction' => 'auto',
            'colorMode' => 'light',
            'primaryColor' => null,
            'uid' => strtolower(\function_exists('wp_generate_password') ? \wp_generate_password(8, false, false) : substr(md5(uniqid('', true)), 0, 8)),
            'themeOverrides' => null,
            'topK' => null,
            'snippetMaxChars' => null,
        );

        list($attrs, $is_preview) = $this->buildShortcodeBlockAttrs(
            $atts,
            $content,
            $attribute_defaults,
            array('themeOverrides')
        );

        return $this->renderShortcodeBlock('smartcloud-ai-kit/doc-search', $attrs, $is_preview);
    }

    /**
     * Add settings page in wp-admin.
     */
    public function createAdminMenu(): void
    {
        $this->admin->addMenu();
    }

    private function defineConstants(): void
    {
        define('SMARTCLOUD_AI_KIT_VERSION', VERSION);
        define('SMARTCLOUD_AI_KIT_DB_VERSION', DB_VERSION);
        define('SMARTCLOUD_AI_KIT_SLUG', 'smartcloud-ai-kit');
        define('SMARTCLOUD_AI_KIT_PATH', plugin_dir_path(__FILE__));
        define('SMARTCLOUD_AI_KIT_URL', plugin_dir_url(__FILE__));
    }

    /**
     * Include admin classes or additional files.
     */
    private function includes(): void
    {
        // Load Composer autoloader
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'vendor/autoload.php')) {
            require_once SMARTCLOUD_AI_KIT_PATH . 'vendor/autoload.php';
        }

        // Logger class
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'admin/logger.php')) {
            require_once SMARTCLOUD_AI_KIT_PATH . 'admin/logger.php';
        }

        // Hub admin classes
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'hub-loader.php')) {
            require_once SMARTCLOUD_AI_KIT_PATH . 'hub-loader.php';
        }

        // Admin classes
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'admin/admin.php')) {
            require_once SMARTCLOUD_AI_KIT_PATH . 'admin/admin.php';
        }
        if (class_exists('\SmartCloud\WPSuite\AiKit\Admin')) {
            $this->admin = new \SmartCloud\WPSuite\AiKit\Admin();
        }

        // KB Content Parser and Converter
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'admin/kb/converter.php')) {
            require_once SMARTCLOUD_AI_KIT_PATH . 'admin/kb/converter.php';
        }
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'admin/kb/parser.php')) {
            require_once SMARTCLOUD_AI_KIT_PATH . 'admin/kb/parser.php';
        }

        // KB Admin classes.
        if (file_exists(SMARTCLOUD_AI_KIT_PATH . 'admin/kb/admin.php')) {
            require_once SMARTCLOUD_AI_KIT_PATH . 'admin/kb/admin.php';
        }
        if (class_exists('\SmartCloud\WPSuite\AiKit\KnowledgeBase\Admin')) {
            $this->kbAdmin = new \SmartCloud\WPSuite\AiKit\KnowledgeBase\Admin();
        }
    }
    private function normalize_shortcode_content(?string $content): string
    {
        if (!is_string($content) || $content === '') {
            return '';
        }

        // Decode entities (editors sometimes entity-encode quotes etc.)
        $text = html_entity_decode($content, ENT_QUOTES, get_bloginfo('charset'));

        // Normalize newlines
        $text = str_replace("\r\n", "\n", $text);

        // Remove wpautop/editor wrapper tags while preserving line structure
        // </p><p> -> newline
        $text = preg_replace('~</p>\s*<p[^>]*>~i', "\n", $text);

        // <br> -> newline
        $text = preg_replace('~<br\s*/?>~i', "\n", $text);

        // Remove remaining <p> wrappers
        $text = preg_replace('~</?p[^>]*>~i', '', $text);

        // Common wrappers from some editors
        $text = preg_replace('~</?div[^>]*>~i', '', $text);
        $text = preg_replace('~</?span[^>]*>~i', '', $text);

        // NBSP -> space
        $text = str_replace("\xC2\xA0", ' ', $text);

        return trim($text);
    }
}

// Bootstrap plugin.
if (defined('SMARTCLOUD_AI_KIT_BOOTSTRAPPED')) {
    return;
}
define('SMARTCLOUD_AI_KIT_BOOTSTRAPPED', true);

add_action('init', 'SmartCloud\WPSuite\AiKit\aikitHubInit', 15);
add_action('init', 'SmartCloud\WPSuite\AiKit\aikitPluginInit', 20);
add_action('plugins_loaded', 'SmartCloud\WPSuite\AiKit\aikitLoaded', 20);
function aikitHubInit()
{
    if (class_exists('\SmartCloud\WPSuite\Hub\AiKitHubLoader')) {
        $loader = loader();
        $loader->init();
    }
}
function aikitPluginInit()
{
    $instance = aikit();
    $instance->init();
}
function aikitLoaded()
{
    $instance = aikit();
    if (class_exists('\SmartCloud\WPSuite\Hub\AiKitHubLoader')) {
        $loader = loader();
        $loader->check();
    }
    $instance->registerWidgets();
}

/**
 * Accessor function
 *
 * @return \SmartCloud\WPSuite\AiKit\AiKit
 */
function aikit()
{
    return AiKit::instance();
}

/**
 * Accessor function
 *
 * @return \SmartCloud\WPSuite\Hub\AiKitHubLoader
 */
function loader()
{
    return \SmartCloud\WPSuite\Hub\AiKitHubLoader::instance('smartcloud-ai-kit/smartcloud-ai-kit.php', 'smartcloud-ai-kit');
}
