<?php
/**
 * Schema Meta Box
 *
 * Adds schema controls to post edit screen
 *
 * @package TamRank
 * @subpackage Schema
 */

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

class TAMRANK_Schema_Meta_Box {

    /**
     * Templates manager instance
     *
     * @var TAMRANK_Schema_Templates
     */
    private $templates;

    /**
     * Detector manager instance
     *
     * @var TAMRANK_Schema_Detector_Manager|null
     */
    private $detector_manager = null;

    /**
     * Initialize the meta box
     *
     * @param TAMRANK_Schema_Templates $templates Templates manager
     */
    public function __construct($templates) {
        $this->templates = $templates;

        // Schema meta box is now integrated into the main SEO meta box as a tab
        // We only need to keep the AJAX handler for schema preview
        add_action('wp_ajax_tamrank_preview_schema', array($this, 'ajax_preview_schema'));

        // Initialiseer detector manager als de klasse bestaat
        if ( class_exists( 'TAMRANK_Schema_Detector_Manager' ) ) {
            $this->detector_manager = TAMRANK_Schema_Detector_Manager::krijg_instantie();
        }
    }


    /**
     * Add meta box to post types that have templates
     */
    public function add_meta_box() {
        $all_templates = $this->templates->get_templates();
        $post_types_with_schema = array();

        // Find all post types that have at least one template
        foreach ($all_templates as $template) {
            $post_types_with_schema = array_merge($post_types_with_schema, $template['post_types']);
        }

        $post_types_with_schema = array_unique($post_types_with_schema);

        // Add meta box to each post type
        foreach ($post_types_with_schema as $post_type) {
            add_meta_box(
                'tamrank_schema_meta_box',
                '<div style="display: flex; align-items: center; gap: 4px;">
            <svg width="20" height="20" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
                <ellipse fill="#10b981" cx="256" cy="256" rx="252.57" ry="246.84"/>
                <g>
                    <path fill="#fff" d="M123.39,300.12c0,10.18.34,17.65,1.36,25.62h-37.45c1.02-7.97,1.36-14.93,1.36-25.62v-85.52h-20c-10.68,0-13.56.17-25.59,1.19v-32.41c5.59.68,14.91,1.19,25.25,1.19h74.23c11.86,0,18.64-.34,26.44-1.19v32.41c-7.63-.85-14.24-1.19-26.44-1.19h-19.15v85.52h0Z"/>
                    <path fill="#fff" d="M264.57,325.74c-1.36-8.14-2.37-12.56-4.07-18.32l-4.58-14.42h-48.3l-4.58,14.42c-2.2,6.79-3.39,12.05-4.24,18.32h-39.65c2.54-5.09,4.07-9.16,8.13-20.7l36.6-102.14c3.05-8.31,4.58-13.4,5.42-18.32h44.23c1.19,4.92,2.37,9.33,5.76,18.32l36.77,102.14c3.22,8.99,5.93,15.95,8.13,20.7h-39.65,0ZM231.51,213.58l-15.76,50.9h31.86l-16.1-50.9h0Z"/>
                    <path fill="#fff" d="M377.59,325.74c-.85-5.94-2.71-12.22-7.29-25.11l-15.59-45.13c-.17-.85-5.25-16.63-5.76-17.99-1.24-4.07-2.15-6.9-2.71-8.48,1.02,10.69,1.69,24.6,1.69,33.6v36.82c0,11.71.34,19.17,1.36,26.3h-33.38c1.02-7.64,1.36-14.76,1.36-26.3v-88.4c0-10.18-.51-19.17-1.36-26.47h44.74c1.19,7.3,2.54,12.73,6.44,23.92l25.42,73.13,25.25-73.13c3.9-11.37,5.25-16.8,6.27-23.92h44.91c-1.02,8.14-1.36,15.1-1.36,26.47v88.4c0,12.9.34,19.51,1.36,26.3h-33.38c1.02-7.81,1.36-14.25,1.36-26.3v-36.99c0-4.07.51-16.8.85-22.06.34-6,.56-9.84.68-11.54-3.73,13.23-5.42,19.34-7.63,25.45l-16.44,46.49c-4.24,12.05-6.44,19.51-7.29,24.94h-29.49Z"/>
                </g>
            </svg>
            <span>Rank™ Schema</span>
        </div>',
                array($this, 'render_meta_box'),
                $post_type,
                'normal',
                'default' // Lower priority than SEO meta box ('high') so Schema appears below it
            );
        }
    }

    /**
     * Render the meta box
     *
     * @param WP_Post $post Current post
     */
    public function render_meta_box($post) {
        wp_nonce_field('tamrank_schema_meta_box', 'tamrank_schema_nonce');

        // Enqueue this meta box's CSS + a src-less handle for its UI script (moved out of
        // inline <style>/<script> for wp.org compliance). Done here so nothing loads unless
        // the meta box actually renders; late enqueues are emitted in the footer.
        wp_enqueue_style('tamrank-schema-meta-box', TAM_RANK_PLUGIN_URL . 'assets/css/schema-meta-box.css', array(), TAM_RANK_VERSION);
        wp_register_script('tamrank-schema-meta-box', false, array('jquery'), TAM_RANK_VERSION, true);
        wp_enqueue_script('tamrank-schema-meta-box');

        // Get current settings
        $enabled = get_post_meta($post->ID, 'tamrank_schema_enabled', true);
        $template_id = get_post_meta($post->ID, 'tamrank_schema_template_id', true);
        $overrides = get_post_meta($post->ID, 'tamrank_schema_overrides', true);

        if ($enabled === '') {
            $enabled = '1'; // Default enabled
        }

        if (!is_array($overrides)) {
            $overrides = array();
        }

        // Get available templates for this post type
        $templates = $this->templates->get_templates_for_post_type($post->post_type);

        if (empty($templates)) {
            echo '<p>' . sprintf(
                /* translators: %1$s: opening anchor tag, %2$s: closing anchor tag */
                esc_html__( 'There are no schema templates for this post type yet. %1$sCreate a template%2$s.', 'tam-rank' ),
                '<a href="' . esc_url(admin_url('admin.php?page=tam-rank-schema')) . '">',
                '</a>'
            ) . '</p>';
            return;
        }

        // Check if template is being changed via URL parameter (from dropdown change)
        if (isset($_GET['schema_template_id'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request inspection (admin page / OAuth callback / menu detection); no state-changing action to protect.
            $url_template_id = sanitize_text_field(wp_unslash($_GET['schema_template_id'])); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request inspection (admin page / OAuth callback / menu detection); no state-changing action to protect.
            // Validate that this template exists and is available for this post type
            if (isset($templates[$url_template_id])) {
                $template_id = $url_template_id;
                // Also save it to post meta so it persists
                update_post_meta($post->ID, 'tamrank_schema_template_id', $template_id);
            }
        }

        // If no template selected, use first one
        if (empty($template_id) || !isset($templates[$template_id])) {
            $template_id = key($templates);
        }

        $current_template = isset($templates[$template_id]) ? $templates[$template_id] : reset($templates);
        $schema_types = tamrank_get_schema_types();
        $schema_config = isset($schema_types[$current_template['schema_type']]) ? $schema_types[$current_template['schema_type']] : null;

        // Handle Custom JSON-LD templates differently
        $is_custom_schema = isset($schema_config['is_custom']) && $schema_config['is_custom'];

        ?>
        <div class="tamrank-schema-meta-box">
            <!-- Groot grijs blok zoals SEO meta boxes -->
            <div style="background: #ECEAE7; padding: 20px; border-radius: 8px; border: 2px solid #e2e8f0;">

                <!-- Enable/Disable Schema & Template Selection + Validation Status -->
                <div style="margin-bottom: 20px; display: flex; align-items: center; justify-content: space-between; gap: 20px;">
                    <!-- Left: Toggle + Template -->
                    <div style="display: flex; align-items: center; gap: 30px; flex: 1;">
                        <!-- Toggle Switch Style -->
                        <div style="display: flex; align-items: center; gap: 12px;">
                            <label class="tam-toggle-switch" style="position: relative; display: inline-block; width: 48px; height: 26px; cursor: pointer;">
                                <input type="checkbox"
                                       name="tamrank_schema_enabled"
                                       value="1"
                                       <?php checked($enabled, '1'); ?>
                                       id="tamrank_schema_enabled"
                                       style="opacity: 0; width: 0; height: 0;">
                                <span class="tam-toggle-track" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(135deg, #e2e8f0 0%, #cbd5e1 100%); transition: all 0.3s ease; border-radius: 13px; box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);"></span>
                                <span class="tam-toggle-thumb" style="position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background: white; transition: all 0.3s ease; border-radius: 50%; box-shadow: 0 2px 4px rgba(0,0,0,0.2);"></span>
                            </label>
                            <strong class="tam-toggle-label" style="color: #475569; font-size: 14px; font-weight: 500; white-space: nowrap;"><?php echo esc_html__( 'Enable Schema Markup', 'tam-rank' ); ?></strong>
                        </div>

                        <div id="schema-template-selector" style="display: flex; align-items: center; gap: 12px; <?php echo esc_attr( $enabled !== '1' ? 'opacity: 0.5; pointer-events: none;' : '' ); ?>">
                            <label for="tamrank_schema_template_id" style="margin: 0; white-space: nowrap; color: #94a3b8; font-size: 13px; font-weight: 500;">
                                <?php echo esc_html__( 'Schema Template', 'tam-rank' ); ?>
                            </label>
                            <select name="tamrank_schema_template_id" id="tamrank_schema_template_id" style="padding: 10px 16px; background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); border: 1px solid #86efac; border-radius: 10px; font-size: 14px; font-weight: 500; color: #166534; cursor: pointer; min-width: 200px;">
                                <?php foreach ($templates as $tid => $tpl): ?>
                                    <option value="<?php echo esc_attr($tid); ?>" <?php selected($template_id, $tid); ?>>
                                        <?php echo esc_html($tpl['name']); ?> (<?php echo esc_html($schema_types[$tpl['schema_type']]['label']); ?>)
                                    </option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                    </div>

                    <!-- Right: Validation Status -->
                    <div class="tam-validation-status" style="display: flex; align-items: center; gap: 8px; padding: 8px 16px; background: #dcfce7; border-radius: 10px;">
                        <div style="width: 20px; height: 20px; background: #22c55e; border-radius: 50%; display: flex; align-items: center; justify-content: center;">
                            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3" style="display: block;">
                                <polyline points="20 6.5 9 17.5 4 12.5"/>
                            </svg>
                        </div>
                        <span style="font-size: 13px; color: #166534; font-weight: 500;"><?php echo esc_html__( 'Schema is valid', 'tam-rank' ); ?></span>
                    </div>
                </div>

                <div id="schema-settings" style="<?php echo esc_attr( $enabled !== '1' ? 'display: none;' : '' ); ?>">

                    <?php
                    // Render schema detectie sectie als detector beschikbaar is
                    $this->render_detectie_sectie( $post );
                    ?>

                    <!-- Grid Layout: Preview Links, Velden Rechts -->
                    <div style="display: grid; grid-template-columns: 40% 60%; gap: 20px;">

                        <!-- Linker Kolom: JSON-LD Preview (40%) -->
                        <div>
                            <div class="schema-preview-sticky" style="background: white; padding: 15px; border-radius: 8px; border: 2px solid #e2e8f0; position: sticky; top: 32px;">
                                <h4 style="color: #0f172a; margin: 0 0 15px 0;"><?php echo esc_html__( 'JSON-LD Preview', 'tam-rank' ); ?></h4>
                                <div id="schema-preview" style="background: #f1f5f9; color: #0f172a; padding: 15px; border-radius: 8px; font-family: monospace; font-size: 11px; max-height: 500px; overflow: auto; border: 2px solid #cbd5e1; margin-bottom: 15px;">
                                    <em style="color: #64748b;"><?php echo esc_html__( 'Generating preview...', 'tam-rank' ); ?></em>
                                </div>

                                <!-- Google Rich Results Test -->
                                <a href="<?php echo esc_url( 'https://search.google.com/test/rich-results?url=' . urlencode( get_permalink( $post ) ) ); ?>"
                                   target="_blank"
                                   class="button tam-btn tam-btn-blue"
                                   style="text-decoration: none; width: 100%; text-align: center; display: block;">
                                    <?php echo esc_html__( 'Open in Google Rich Results Test', 'tam-rank' ); ?>
                                </a>
                            </div>
                        </div>

                        <!-- Rechter Kolom: Velden (60%) -->
                        <div style="padding-right: 10px;">
                            <div class="schema-fields-container">
                                <?php if ($is_custom_schema): ?>
                                    <!-- Custom JSON-LD Template Message -->
                                    <div style="background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); padding: 25px; border-radius: 12px; border: 2px solid #86efac; text-align: center;">
                                        <div style="width: 60px; height: 60px; background: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 15px; box-shadow: 0 4px 12px rgba(37, 172, 117, 0.2);">
                                            <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2">
                                                <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
                                            </svg>
                                        </div>
                                        <h3 style="color: #166534; margin: 0 0 10px 0; font-size: 18px;"><?php echo esc_html__( 'Custom JSON-LD Template', 'tam-rank' ); ?></h3>
                                        <p style="color: #15803d; margin: 0 0 20px 0; font-size: 14px; line-height: 1.6;">
                                            <?php echo esc_html__( 'This is a Custom JSON-LD template. The schema markup is determined entirely by the JSON-LD code you have set in the Template Editor.', 'tam-rank' ); ?>
                                        </p>
                                        <a href="<?php echo esc_url(admin_url('admin.php?page=tam-rank-schema&action=edit&template_id=' . urlencode($template_id))); ?>"
                                           class="button tam-btn tam-btn-green"
                                           style="display: inline-flex; align-items: center; gap: 8px; padding: 12px 24px; font-size: 14px; font-weight: 600; text-decoration: none;">
                                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                                <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
                                                <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
                                            </svg>
                                            <?php tamrank_e('edit_jsonld_template', 'Edit JSON-LD in Template Editor'); ?>
                                        </a>
                                    </div>
                                <?php else: ?>
                                    <?php
                                    // Sort fields: manual fields first, then automatic fields
                                    $sorted_mappings = array();
                                    $manual_fields = array();
                                    $automatic_fields = array();

                                    $field_mappings = isset($current_template['field_mappings']) ? $current_template['field_mappings'] : array();

                                    foreach ($field_mappings as $property => $mapping) {
                                        if ($mapping['source'] === 'manual' || !empty($overrides[$property])) {
                                            $manual_fields[$property] = $mapping;
                                        } else {
                                            $automatic_fields[$property] = $mapping;
                                        }
                                    }

                                    // Merge: manual fields first, then automatic
                                    $sorted_mappings = array_merge($manual_fields, $automatic_fields);
                                    ?>

                                    <?php foreach ($sorted_mappings as $property => $mapping):
                                        $prop_config = isset($schema_config['properties'][$property]) ? $schema_config['properties'][$property] : array();
                                        $field_type = isset($prop_config['type']) ? $prop_config['type'] : 'text';
                                        $is_manual = ($mapping['source'] === 'manual');
                                        $is_disabled = !$is_manual && empty($overrides[$property]);

                                        // Determine field value based on source
                                        $field_value = '';
                                        if (!empty($overrides[$property])) {
                                            $field_value = $overrides[$property];
                                        } elseif (!$is_manual) {
                                            // Show the source type for non-manual fields
                                            $source_labels = array(
                                                'post_title' => tamrank__( 'source_post_title', 'Page title' ),
                                                'meta_description' => tamrank__( 'source_meta_description', 'Meta description' ),
                                                'excerpt' => tamrank__( 'source_excerpt', 'Excerpt' ),
                                                'content_excerpt' => tamrank__( 'source_content_excerpt', 'Content excerpt' ),
                                                'featured_image' => tamrank__( 'source_featured_image', 'Featured image' ),
                                                'first_content_image' => tamrank__( 'source_first_content_image', 'First content image' ),
                                                'author_name' => tamrank__( 'source_author_name', 'Author name' ),
                                                'author_url' => tamrank__( 'source_author_url', 'Author URL' ),
                                                'post_date' => tamrank__( 'source_post_date', 'Publication date' ),
                                                'post_modified' => tamrank__( 'source_post_modified', 'Modified date' ),
                                                'global_organization' => tamrank__( 'source_global_organization', 'Global organization' ),
                                                'global_logo' => tamrank__( 'source_global_logo', 'Global logo' ),
                                                'custom_field' => sprintf( tamrank__( 'source_custom_field_named', 'Automatic (Custom Field: %s)' ), (isset($mapping['custom_field']) ? $mapping['custom_field'] : '') )
                                            );
                                            $field_value = isset($source_labels[$mapping['source']]) ? $source_labels[$mapping['source']] : sprintf( tamrank__( 'source_automatic_generic', 'Automatic (%s)' ), $mapping['source'] );
                                        }
                                    ?>
                                        <div style="background: white; padding: 15px 20px; border-radius: 8px; border: 2px solid <?php echo esc_attr( $is_disabled ? '#e2e8f0' : '#e2e8f0' ); ?>; margin-bottom: 15px; <?php echo esc_attr( $is_disabled ? 'opacity: 0.75;' : '' ); ?>">
                                            <label for="schema_override_<?php echo esc_attr($property); ?>" style="display: block; margin-bottom: 8px;">
                                                <strong style="color: #0f172a; font-size: 14px;"><?php echo esc_html(isset($prop_config['label']) ? $prop_config['label'] : $property); ?></strong>
                                                <?php if (isset($prop_config['required']) && $prop_config['required']): ?>
                                                    <span style="color: #f43f5e; font-weight: 700;">*</span>
                                                <?php endif; ?>
                                            </label>

                                            <?php if ($field_type === 'image'): ?>
                                                <input type="url"
                                                       name="tamrank_schema_overrides[<?php echo esc_attr($property); ?>]"
                                                       id="schema_override_<?php echo esc_attr($property); ?>"
                                                       value="<?php echo esc_attr(isset($overrides[$property]) ? $overrides[$property] : ''); ?>"
                                                       class="widefat schema-field-input"
                                                       style="padding: 12px 15px; border: 2px solid #cbd5e1; border-radius: 8px; background: <?php echo esc_attr( $is_disabled ? '#f1f5f9' : '#f1f5f9' ); ?>; width: 100%;"
                                                       placeholder="<?php echo $is_disabled ? esc_attr($field_value) : 'https://example.com/image.jpg'; ?>"
                                                       <?php echo $is_disabled ? 'disabled' : ''; ?>>
                                            <?php elseif ($field_type === 'select' && isset($prop_config['options'])): ?>
                                                <select name="tamrank_schema_overrides[<?php echo esc_attr($property); ?>]"
                                                        id="schema_override_<?php echo esc_attr($property); ?>"
                                                        class="widefat schema-field-input"
                                                        style="padding: 12px 15px; border: 2px solid #cbd5e1; border-radius: 8px; background: <?php echo esc_attr( $is_disabled ? '#f1f5f9' : '#f1f5f9' ); ?>; width: 100%;"
                                                        <?php echo $is_disabled ? 'disabled' : ''; ?>>
                                                    <?php if ($is_disabled): ?>
                                                        <option value=""><?php echo esc_html($field_value); ?></option>
                                                    <?php else: ?>
                                                        <option value=""><?php echo esc_html__( '-- Select source --', 'tam-rank' ); ?></option>
                                                        <?php foreach ($prop_config['options'] as $opt_value => $opt_label): ?>
                                                            <option value="<?php echo esc_attr($opt_value); ?>"
                                                                    <?php selected(isset($overrides[$property]) ? $overrides[$property] : '', $opt_value); ?>>
                                                                <?php echo esc_html($opt_label); ?>
                                                            </option>
                                                        <?php endforeach; ?>
                                                    <?php endif; ?>
                                                </select>
                                            <?php else: ?>
                                                <input type="text"
                                                       name="tamrank_schema_overrides[<?php echo esc_attr($property); ?>]"
                                                       id="schema_override_<?php echo esc_attr($property); ?>"
                                                       value="<?php echo esc_attr(isset($overrides[$property]) ? $overrides[$property] : ''); ?>"
                                                       class="widefat schema-field-input"
                                                       style="padding: 12px 15px; border: 2px solid #cbd5e1; border-radius: 8px; background: <?php echo esc_attr( $is_disabled ? '#f1f5f9' : '#f1f5f9' ); ?>; width: 100%;"
                                                       placeholder="<?php echo $is_disabled ? esc_attr($field_value) : esc_attr(isset($prop_config['placeholder']) ? $prop_config['placeholder'] : ''); ?>"
                                                       <?php echo $is_disabled ? 'disabled' : ''; ?>>
                                            <?php endif; ?>

                                            <?php if ($is_disabled): ?>
                                                <p style="margin: 8px 0 0 0; font-size: 12px; color: #64748b; display: flex; align-items: center; gap: 6px;">
                                                    <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
                                                        <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
                                                    </svg>
                                                    <span><?php echo sprintf(
                                                        /* translators: %1$s: opening anchor tag, %2$s: closing anchor tag */
                                                        esc_html__( 'This field is filled in automatically. Edit the source in the %1$sTemplate Editor%2$s.', 'tam-rank' ),
                                                        '<a href="' . esc_url(admin_url('admin.php?page=tam-rank-schema&action=edit&template_id=' . urlencode($template_id))) . '" style="color: #10b981; text-decoration: none; font-weight: 500;">',
                                                        '</a>'
                                                    ); ?></span>
                                                </p>
                                            <?php endif; ?>
                                        </div>
                                    <?php endforeach; ?>
                                <?php endif; ?>
                            </div>
                        </div>

                    </div>
                </div>

            </div>
        </div>

        <?php ob_start(); ?>
        jQuery(document).ready(function($) {
            // Check if we came from a template change (URL has schema_template_id parameter)
            var urlParams = new URLSearchParams(window.location.search);
            var cameFromTemplateChange = urlParams.has('schema_template_id');

            if (cameFromTemplateChange) {
                // Open the meta box if it's collapsed
                var $metaBox = $('#tamrank_schema_meta_box');
                if ($metaBox.hasClass('closed')) {
                    $metaBox.removeClass('closed');
                    $metaBox.find('.inside').show();
                }

                // Scroll to the meta box after a short delay (wait for Gutenberg)
                setTimeout(function() {
                    $metaBox[0].scrollIntoView({
                        behavior: 'smooth',
                        block: 'start'
                    });

                    // Add visual highlight
                    setTimeout(function() {
                        $metaBox.css({
                            'box-shadow': '0 0 20px rgba(37, 172, 117, 0.5)',
                            'transition': 'box-shadow 0.3s ease'
                        });

                        setTimeout(function() {
                            $metaBox.css('box-shadow', '');
                        }, 2000);
                    }, 500);
                }, 500);

                // Clean the URL (remove the parameter) without reloading
                var cleanUrl = new URL(window.location.href);
                cleanUrl.searchParams.delete('schema_template_id');
                window.history.replaceState({}, document.title, cleanUrl.toString());
            }

            // Toggle schema settings visibility
            $('#tamrank_schema_enabled').on('change', function() {
                $('#schema-settings').toggle(this.checked);

                // Update template selector opacity
                if (this.checked) {
                    $('#schema-template-selector').css({'opacity': '1', 'pointer-events': 'auto'});
                } else {
                    $('#schema-template-selector').css({'opacity': '0.5', 'pointer-events': 'none'});
                }
            });

            // Reload page when template changes to show correct fields
            $('#tamrank_schema_template_id').on('change', function() {
                var $sel = $(this);
                var newTemplateId = $sel.val();
                window.TamRank.confirm({
                    title: '<?php echo esc_js(tamrank__('schema_template_change_title', 'Change template?')); ?>',
                    message: '<?php echo esc_js(tamrank__('schema_template_change_message', 'The page will be reloaded. Unsaved changes will be lost.')); ?>',
                    confirmLabel: '<?php echo esc_js(tamrank__('schema_template_change_confirm', 'Continue')); ?>',
                    variant: 'default'
                }).then(function (ok) {
                    if (!ok) {
                        $sel.val($sel.data('original-value'));
                        return;
                    }
                    var url = new URL(window.location.href);
                    url.searchParams.set('schema_template_id', newTemplateId);
                    window.location.href = url.toString();
                });
            }).data('original-value', $('#tamrank_schema_template_id').val());

            // Function to update schema preview
            function updateSchemaPreview() {
                var postId = <?php echo intval($post->ID); ?>;
                var templateId = $('#tamrank_schema_template_id').val();

                // Bepaal de schema bron (automatisch is default als detectie beschikbaar is)
                var bron = 'automatisch';
                <?php
                $schema_bron = get_post_meta($post->ID, 'tamrank_schema_bron', true);
                if (!empty($schema_bron)) {
                    echo "bron = '" . esc_js($schema_bron) . "';";
                }
                ?>

                // Collect override values
                var overrides = {};
                $('.schema-fields-container input, .schema-fields-container select').each(function() {
                    var name = $(this).attr('name');
                    if (name && name.indexOf('tamrank_schema_overrides') !== -1) {
                        // Extract property name from name attribute
                        var matches = name.match(/\[([^\]]+)\]/);
                        if (matches && matches[1]) {
                            var value = $(this).val();
                            if (value) {
                                overrides[matches[1]] = value;
                            }
                        }
                    }
                });

                $('#schema-preview').html('<em style="color: #94a3b8;"><?php echo esc_js(tamrank__('schema_preview_generating', 'Generating preview...')); ?></em>');

                $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    data: {
                        action: 'tamrank_preview_schema',
                        nonce: '<?php echo esc_js(wp_create_nonce('tamrank_schema_preview')); ?>',
                        post_id: postId,
                        template_id: templateId,
                        bron: bron,
                        overrides: overrides
                    },
                    success: function(response) {
                        if (response.success) {
                            var formatted = JSON.stringify(response.data, null, 2);
                            $('#schema-preview').html('<pre>' + escapeHtml(formatted) + '</pre>');
                        } else {
                            $('#schema-preview').html('<em style="color: #f43f5e;"><?php echo esc_js(tamrank__('schema_preview_error_prefix', 'Error:')); ?> ' +
                                escapeHtml(response.data || '<?php echo esc_js(tamrank__('schema_preview_error_unknown', 'Unknown error')); ?>') + '</em>');
                        }
                    },
                    error: function(xhr, status, error) {
                        $('#schema-preview').html('<em style="color: #f43f5e;"><?php echo esc_js(tamrank__('schema_preview_load_error', 'Error loading preview:')); ?> ' + escapeHtml(error || status) + '</em>');
                    }
                });
            }

            // Escape HTML for safe display
            function escapeHtml(text) {
                var map = {
                    '&': '&amp;',
                    '<': '&lt;',
                    '>': '&gt;',
                    '"': '&quot;',
                    "'": '&#039;'
                };
                return text.replace(/[&<>"']/g, function(m) { return map[m]; });
            }

            // Update preview on field changes
            $('.schema-fields-container input, .schema-fields-container select').on('change keyup', function() {
                clearTimeout(window.tamrankSchemaPreviewTimeout);
                window.tamrankSchemaPreviewTimeout = setTimeout(updateSchemaPreview, 500);
            });

            // Initial preview load
            updateSchemaPreview();

        });
        <?php wp_add_inline_script('tamrank-schema-meta-box', ob_get_clean()); ?>
        <?php
    }

    /**
     * Render schema detectie sectie in metabox
     *
     * @param WP_Post $post Huidige post
     */
    private function render_detectie_sectie( $post ) {
        // Controleer of detector manager beschikbaar is
        if ( ! $this->detector_manager ) {
            return;
        }

        // Haal detectie data op
        $metabox_data = $this->detector_manager->krijg_metabox_data( $post->ID );
        $detectie     = $metabox_data['detectie'];
        $handmatig    = $metabox_data['handmatig'];
        $effectief    = $metabox_data['effectief'];

        // Bepaal of er een aanbeveling is
        $heeft_detectie = $detectie && $detectie['is_geldig'];
        $heeft_handmatig = $metabox_data['heeft_handmatig'];
        ?>
        <div class="tamrank-schema-detectie-sectie" style="margin-bottom: 20px;">
            <!-- Aanbeveling Banner -->
            <?php if ( $heeft_detectie && ! $heeft_handmatig ) : ?>
            <div class="tam-detectie-aanbeveling" style="background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); border: 2px solid #7dd3fc; border-radius: 12px; padding: 20px; margin-bottom: 15px;">
                <div style="display: flex; align-items: flex-start; gap: 15px;">
                    <!-- Icon -->
                    <div style="flex-shrink: 0; width: 48px; height: 48px; background: linear-gradient(135deg, #0ea5e9 0%, #38bdf8 100%); border-radius: 12px; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3);">
                        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
                            <path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/>
                        </svg>
                    </div>
                    <!-- Content -->
                    <div style="flex: 1;">
                        <h4 style="margin: 0 0 8px 0; color: #0369a1; font-size: 16px; font-weight: 600;">
                            <?php tamrank_e( 'schema_recommendation', 'Schema Recommendation' ); ?>
                        </h4>
                        <p style="margin: 0 0 12px 0; color: #0c4a6e; font-size: 14px; line-height: 1.5;">
                            <?php
                            echo wp_kses_post( sprintf(
                                /* translators: 1: Schema type, 2: Confidence percentage */
                                tamrank__( 'schema_recommendation_desc', 'Based on the content we recommend %1$s. Confidence: %2$s' ),
                                '<strong>' . esc_html( $detectie['hoofd_schema'] ) . '</strong>',
                                '<span style="background: #0ea5e9; color: white; padding: 2px 8px; border-radius: 4px; font-size: 12px; font-weight: 600;">' . esc_html( $detectie['label'] ) . ' (' . round( $detectie['betrouwbaarheid'] * 100 ) . '%)</span>'
                            ) );
                            ?>
                        </p>
                        <?php if ( ! empty( $detectie['extra_schemas'] ) ) : ?>
                        <p style="margin: 0 0 12px 0; color: #0c4a6e; font-size: 13px;">
                            <?php tamrank_e( 'schema_extra_found', 'Extra schemas found:' ); ?>
                            <?php foreach ( $detectie['extra_schemas'] as $extra ) : ?>
                            <span style="background: #e0f2fe; color: #0369a1; padding: 2px 8px; border-radius: 4px; font-size: 12px; margin-left: 4px;"><?php echo esc_html( $extra ); ?></span>
                            <?php endforeach; ?>
                        </p>
                        <?php endif; ?>
                        <div style="display: flex; gap: 10px; flex-wrap: wrap;">
                            <button type="button" class="button tam-btn tam-btn-green tam-accepteer-schema" data-post-id="<?php echo esc_attr( $post->ID ); ?>" style="display: inline-flex; align-items: center; gap: 6px;">
                                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <polyline points="20 6 9 17 4 12"/>
                                </svg>
                                <?php tamrank_e( 'schema_accept_recommendation', 'Accept Recommendation' ); ?>
                            </button>
                            <button type="button" class="button tam-btn tam-btn-outline tam-toon-handmatig" style="display: inline-flex; align-items: center; gap: 6px;">
                                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
                                    <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
                                </svg>
                                <?php tamrank_e( 'schema_choose_manual', 'Choose Manually' ); ?>
                            </button>
                            <button type="button" class="button tam-btn tam-detecteer-opnieuw" data-post-id="<?php echo esc_attr( $post->ID ); ?>" style="display: inline-flex; align-items: center; gap: 6px; color: #64748b;">
                                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <polyline points="23 4 23 10 17 10"/>
                                    <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/>
                                </svg>
                                <?php tamrank_e( 'schema_detect_again', 'Detect Again' ); ?>
                            </button>
                        </div>
                    </div>
                </div>
            </div>
            <?php elseif ( $heeft_handmatig ) : ?>
            <!-- Handmatige keuze actief -->
            <div class="tam-detectie-handmatig" style="background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); border: 2px solid #86efac; border-radius: 12px; padding: 15px 20px; margin-bottom: 15px;">
                <div style="display: flex; align-items: center; justify-content: space-between; gap: 15px; flex-wrap: wrap;">
                    <div style="display: flex; align-items: center; gap: 12px;">
                        <div style="width: 36px; height: 36px; background: #22c55e; border-radius: 8px; display: flex; align-items: center; justify-content: center;">
                            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" style="display: block;">
                                <polyline points="20 6.5 9 17.5 4 12.5"/>
                            </svg>
                        </div>
                        <div>
                            <span style="color: #166534; font-weight: 600; font-size: 14px;">
                                <?php tamrank_e( 'schema_manually_chosen', 'Manually chosen:' ); ?>
                            </span>
                            <strong style="color: #166534; font-size: 15px; margin-left: 6px;">
                                <?php echo esc_html( $handmatig['hoofd_type'] ); ?>
                            </strong>
                            <?php if ( ! empty( $handmatig['extra_types'] ) ) : ?>
                            <span style="color: #15803d; font-size: 13px; margin-left: 6px;">
                                + <?php echo esc_html( implode( ', ', $handmatig['extra_types'] ) ); ?>
                            </span>
                            <?php endif; ?>
                        </div>
                    </div>
                    <div style="display: flex; gap: 8px;">
                        <button type="button" class="button tam-btn tam-btn-outline tam-toon-handmatig" style="font-size: 13px;">
                            <?php tamrank_e( 'change', 'Change' ); ?>
                        </button>
                        <button type="button" class="button tam-btn tam-reset-naar-auto" data-post-id="<?php echo esc_attr( $post->ID ); ?>" style="font-size: 13px; color: #64748b;">
                            <?php tamrank_e( 'back_to_automatic', 'Back to Automatic' ); ?>
                        </button>
                    </div>
                </div>
            </div>
            <?php elseif ( ! $heeft_detectie ) : ?>
            <!-- Nog geen detectie uitgevoerd -->
            <div class="tam-detectie-leeg" style="background: linear-gradient(135deg, #fefce8 0%, #fef9c3 100%); border: 2px solid #fde047; border-radius: 12px; padding: 15px 20px; margin-bottom: 15px;">
                <div style="display: flex; align-items: center; justify-content: space-between; gap: 15px; flex-wrap: wrap;">
                    <div style="display: flex; align-items: center; gap: 12px;">
                        <div style="width: 36px; height: 36px; background: #eab308; border-radius: 8px; display: flex; align-items: center; justify-content: center;">
                            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
                                <circle cx="12" cy="12" r="10"/>
                                <line x1="12" y1="16" x2="12" y2="12"/>
                                <line x1="12" y1="8" x2="12.01" y2="8"/>
                            </svg>
                        </div>
                        <span style="color: #854d0e; font-size: 14px;">
                            <?php tamrank_e( 'schema_no_detection', 'No schema detected yet. Click "Detect Schema" or save the post.' ); ?>
                        </span>
                    </div>
                    <div style="display: flex; gap: 8px;">
                        <button type="button" class="button tam-btn tam-btn-blue tam-detecteer-opnieuw" data-post-id="<?php echo esc_attr( $post->ID ); ?>" style="display: inline-flex; align-items: center; gap: 6px;">
                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                <circle cx="11" cy="11" r="8"/>
                                <line x1="21" y1="21" x2="16.65" y2="16.65"/>
                            </svg>
                            <?php tamrank_e( 'schema_detect', 'Detect Schema' ); ?>
                        </button>
                        <button type="button" class="button tam-btn tam-btn-outline tam-toon-handmatig" style="font-size: 13px;">
                            <?php tamrank_e( 'schema_choose_manual', 'Choose Manually' ); ?>
                        </button>
                    </div>
                </div>
            </div>
            <?php endif; ?>

            <!-- Handmatige Selectie Panel (verborgen tot actief) -->
            <div class="tam-handmatige-selectie" style="display: none; background: white; border: 2px solid #e2e8f0; border-radius: 12px; padding: 20px; margin-bottom: 15px;">
                <h4 style="margin: 0 0 15px 0; color: #0f172a; font-size: 15px; font-weight: 600;">
                    <?php tamrank_e( 'schema_manual_selection', 'Manual Schema Selection' ); ?>
                </h4>

                <!-- Hoofd Schema Type -->
                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 8px; color: #475569; font-size: 13px; font-weight: 500;">
                        <?php tamrank_e( 'schema_main_type', 'Main Schema Type' ); ?> <span style="color: #f43f5e;">*</span>
                    </label>
                    <select name="tamrank_handmatig_schema_type" id="tamrank_handmatig_schema_type" style="width: 100%; padding: 10px 15px; border: 2px solid #cbd5e1; border-radius: 8px; font-size: 14px;">
                        <option value=""><?php tamrank_e( 'schema_select_type_placeholder', '-- Select schema type --' ); ?></option>
                        <?php foreach ( $metabox_data['beschikbare_types'] as $type ) : ?>
                        <option value="<?php echo esc_attr( $type ); ?>" <?php selected( $heeft_handmatig ? $handmatig['hoofd_type'] : '', $type ); ?>>
                            <?php echo esc_html( $type ); ?>
                        </option>
                        <?php endforeach; ?>
                    </select>
                </div>

                <!-- Extra Schema Types -->
                <div style="margin-bottom: 15px;">
                    <label style="display: block; margin-bottom: 8px; color: #475569; font-size: 13px; font-weight: 500;">
                        <?php tamrank_e( 'schema_extra_types', 'Extra Schema Types (optional)' ); ?>
                    </label>
                    <div style="display: flex; flex-wrap: wrap; gap: 10px;">
                        <?php foreach ( $metabox_data['extra_schema_types'] as $extra_type ) : ?>
                        <label style="display: flex; align-items: center; gap: 6px; padding: 8px 12px; background: #f1f5f9; border: 1px solid #e2e8f0; border-radius: 6px; cursor: pointer; font-size: 13px; color: #475569;">
                            <input type="checkbox"
                                   name="tamrank_handmatig_extra_schemas[]"
                                   value="<?php echo esc_attr( $extra_type ); ?>"
                                   <?php checked( $heeft_handmatig && in_array( $extra_type, $handmatig['extra_types'], true ) ); ?>
                                   style="margin: 0;">
                            <?php echo esc_html( $extra_type ); ?>
                        </label>
                        <?php endforeach; ?>
                    </div>
                </div>

                <!-- Actie buttons -->
                <div style="display: flex; gap: 10px; justify-content: flex-end;">
                    <button type="button" class="button tam-btn tam-verberg-handmatig">
                        <?php tamrank_e( 'cancel', 'Cancel' ); ?>
                    </button>
                    <button type="button" class="button tam-btn tam-btn-green tam-sla-handmatig-op" data-post-id="<?php echo esc_attr( $post->ID ); ?>">
                        <?php tamrank_e( 'save', 'Save' ); ?>
                    </button>
                </div>
            </div>

            <!-- Hidden input for nonce -->
            <input type="hidden" id="tamrank_detectie_nonce" value="<?php echo esc_attr( $metabox_data['nonce'] ); ?>">
        </div>
        <?php
    }

    /**
     * AJAX handler to preview schema
     */
    public function ajax_preview_schema() {
        check_ajax_referer('tamrank_schema_preview', 'nonce');

        $post_id = intval($_POST['post_id'] ?? 0);
        $template_id = isset($_POST['template_id']) ? sanitize_text_field(wp_unslash($_POST['template_id'])) : '';
        $bron = isset($_POST['bron']) ? sanitize_text_field(wp_unslash($_POST['bron'])) : 'template';
        $overrides = isset($_POST['overrides']) ? map_deep(wp_unslash($_POST['overrides']), 'sanitize_text_field') : array();

        if (!current_user_can('edit_post', $post_id)) {
            wp_send_json_error(array('message' => tamrank__('error_permission_denied', 'You do not have permission for this action.'), 'code' => 'permission_denied'));
            return;
        }

        $post = get_post($post_id);
        if (!$post) {
            wp_send_json_error(array('message' => tamrank__('error_invalid_post', 'This post could not be found.'), 'code' => 'not_found'));
            return;
        }

        // Als bron "automatisch" is, toon gedetecteerde schema
        if ($bron === 'automatisch') {
            return $this->preview_automatisch_schema($post_id, $post);
        }

        // Als bron "handmatig" is, toon handmatig gekozen schema
        if ($bron === 'handmatig') {
            return $this->preview_handmatig_schema($post_id, $post);
        }

        // Anders: template-gebaseerde preview
        $template = $this->templates->get_template($template_id);
        if (!$template) {
            wp_send_json_error(array('message' => tamrank__('error_template_not_found', 'The template could not be found.'), 'code' => 'not_found'));
            return;
        }

        // Get schema manager and render instance
        $schema_manager = tamrank_get_schema_manager();
        if (!$schema_manager) {
            wp_send_json_error(array('message' => tamrank__('error_schema_manager', 'The schema manager is not available.'), 'code' => 'not_found'));
            return;
        }

        $settings = $schema_manager->get_settings();

        // Check if this is a Custom JSON-LD template
        $schema_types = tamrank_get_schema_types();
        $schema_config = isset($schema_types[$template['schema_type']]) ? $schema_types[$template['schema_type']] : null;
        $is_custom_schema = isset($schema_config['is_custom']) && $schema_config['is_custom'];

        if ($is_custom_schema) {
            // For Custom JSON-LD templates, check if custom JSON-LD is enabled and has code
            $custom_enabled = isset($template['custom_jsonld_enabled']) ? $template['custom_jsonld_enabled'] : false;
            $custom_jsonld = isset($template['custom_jsonld_code']) ? $template['custom_jsonld_code'] : '';

            if (!$custom_enabled) {
                wp_send_json_error(array('message' => tamrank__('error_jsonld_disabled', 'Custom JSON-LD is not enabled. Enable it in the Template Editor.'), 'code' => 'not_found'));
                return;
            }

            if (empty($custom_jsonld)) {
                wp_send_json_error(array('message' => tamrank__('error_jsonld_empty', 'No Custom JSON-LD code defined. Add JSON-LD code in the Template Editor.'), 'code' => 'not_found'));
                return;
            }

            // Try to decode the JSON-LD
            $schema = json_decode($custom_jsonld, true);

            if (json_last_error() !== JSON_ERROR_NONE) {
                wp_send_json_error(array('message' => sprintf(tamrank__('error_jsonld_invalid', 'Invalid JSON-LD: %s'), json_last_error_msg()), 'code' => 'missing_parameter'));
                return;
            }

            wp_send_json_success($schema);
            return;
        }

        // Build schema with overrides for standard templates
        $schema = array(
            '@type' => $template['schema_type']
        );

        // Sanitize overrides
        $sanitized_overrides = array();
        foreach ($overrides as $key => $value) {
            $sanitized_overrides[sanitize_text_field($key)] = sanitize_text_field($value);
        }

        // Build each property based on field mappings
        $field_mappings = isset($template['field_mappings']) ? $template['field_mappings'] : array();
        foreach ($field_mappings as $property => $mapping) {
            // Check if there's an override
            if (isset($sanitized_overrides[$property]) && !empty($sanitized_overrides[$property])) {
                $value = $sanitized_overrides[$property];
            } else {
                $value = $this->get_preview_field_value($post, $mapping, $settings);
            }

            if (!empty($value)) {
                $schema[$property] = $value;
            }
        }

        // Add @id for linking
        $schema['@id'] = get_permalink($post_id) . '#primary';

        // Link to organization if publisher field exists
        if (isset($schema['publisher'])) {
            $schema['publisher'] = array('@id' => home_url('/#organization'));
        }

        wp_send_json_success($schema);
    }

    /**
     * Preview automatisch gedetecteerd schema
     *
     * @param int $post_id Post ID
     * @param WP_Post $post Post object
     */
    private function preview_automatisch_schema($post_id, $post) {
        // Buffer output om PHP warnings/notices te vangen die de JSON zouden breken
        ob_start();

        // Gebruik de Schema Render class voor consistente output
        $schema_manager = tamrank_get_schema_manager();
        if (!$schema_manager) {
            ob_end_clean();
            wp_send_json_error(array('message' => tamrank__('error_schema_manager', 'The schema manager is not available.'), 'code' => 'not_found'));
            return;
        }

        $renderer = $schema_manager->get_renderer();
        if (!$renderer) {
            ob_end_clean();
            wp_send_json_error(array('message' => tamrank__('error_schema_renderer', 'The schema renderer is not available.'), 'code' => 'not_found'));
            return;
        }

        // Gebruik dezelfde logica als de echte schema output (met gecachete content voor snellere preview)
        try {
            $schema = $renderer->get_schema_preview($post, 'automatisch');
        } catch (Exception $e) {
            ob_end_clean();
            wp_send_json_error(array('message' => sprintf(tamrank__('error_schema_generate', 'Error generating schema: %s'), $e->getMessage()), 'code' => 'request_failed'));
            return;
        }

        // Discard any stray buffered output before returning JSON.
        ob_get_clean();

        if (!$schema) {
            wp_send_json_error(array('message' => tamrank__('error_no_schema', 'No schema detected. Click "Detect Schema" to start.'), 'code' => 'not_found'));
            return;
        }

        wp_send_json_success($schema);
    }

    /**
     * Preview handmatig gekozen schema
     *
     * @param int $post_id Post ID
     * @param WP_Post $post Post object
     */
    private function preview_handmatig_schema($post_id, $post) {
        // Buffer output om PHP warnings/notices te vangen die de JSON zouden breken
        ob_start();

        // Gebruik de Schema Render class voor consistente output
        $schema_manager = tamrank_get_schema_manager();
        if (!$schema_manager) {
            ob_end_clean();
            wp_send_json_error(array('message' => tamrank__('error_schema_manager', 'The schema manager is not available.'), 'code' => 'not_found'));
            return;
        }

        $renderer = $schema_manager->get_renderer();
        if (!$renderer) {
            ob_end_clean();
            wp_send_json_error(array('message' => tamrank__('error_schema_renderer', 'The schema renderer is not available.'), 'code' => 'not_found'));
            return;
        }

        // Gebruik dezelfde logica als de echte schema output
        try {
            $schema = $renderer->get_schema_preview($post, 'handmatig');
        } catch (Exception $e) {
            ob_end_clean();
            wp_send_json_error(array('message' => sprintf(tamrank__('error_schema_generate', 'Error generating schema: %s'), $e->getMessage()), 'code' => 'request_failed'));
            return;
        }

        // Discard any stray buffered output before returning JSON.
        ob_get_clean();

        if (!$schema) {
            wp_send_json_error(array('message' => tamrank__('error_no_manual_schema', 'No manual schema selected.'), 'code' => 'not_found'));
            return;
        }

        wp_send_json_success($schema);
    }


    /**
     * Extract FAQ items from post content
     * Gebruikt dezelfde logica als de frontend renderer
     * Ondersteunt: Divi shortcodes, Divi HTML, Elementor, standaard headings, Vraag/Antwoord patronen
     *
     * @param WP_Post $post Post object
     * @return array FAQ items
     */
    private function extract_faq_items($post) {
        $items = array();
        $content = $post->post_content;

        // ============================================
        // DIVI SHORTCODE PATRONEN (database opslag)
        // ============================================

        // Patroon 0a: Divi Toggle SHORTCODE met title attribuut
        // Voorbeeld: [et_pb_toggle title="Dit is een vraag?"]Antwoord hier[/et_pb_toggle]
        if (preg_match_all('/\[et_pb_toggle[^\]]*title="([^"]+)"[^\]]*\](.*?)\[\/et_pb_toggle\]/is', $content, $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                if (count($items) >= 10) break;

                $question = wp_strip_all_tags(trim($match[1]));
                $answer = wp_strip_all_tags(trim($match[2]));

                if (!empty($question) && !empty($answer) && strlen($answer) > 5) {
                    $items[] = array(
                        '@type' => 'Question',
                        'name' => $question,
                        'acceptedAnswer' => array(
                            '@type' => 'Answer',
                            'text' => $answer
                        )
                    );
                }
            }
        }

        // Patroon 0b: Divi Accordion Item SHORTCODE
        // Voorbeeld: [et_pb_accordion_item title="Vraag?"]Antwoord[/et_pb_accordion_item]
        if (empty($items)) {
            if (preg_match_all('/\[et_pb_accordion_item[^\]]*title="([^"]+)"[^\]]*\](.*?)\[\/et_pb_accordion_item\]/is', $content, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (count($items) >= 10) break;

                    $question = wp_strip_all_tags(trim($match[1]));
                    $answer = wp_strip_all_tags(trim($match[2]));

                    if (!empty($question) && !empty($answer) && strlen($answer) > 5) {
                        $items[] = array(
                            '@type' => 'Question',
                            'name' => $question,
                            'acceptedAnswer' => array(
                                '@type' => 'Answer',
                                'text' => $answer
                            )
                        );
                    }
                }
            }
        }

        // ============================================
        // DIVI HTML PATRONEN (gerenderde frontend)
        // ============================================

        // Patroon 1: Divi Toggle/Accordion modules - Meest exacte match
        // Voorbeeld: <h5 class="et_pb_toggle_title">Vraag?</h5><div class="et_pb_toggle_content clearfix">Antwoord</div>
        if (empty($items)) {
            if (preg_match_all('/<h[1-6]\s+class="et_pb_toggle_title"[^>]*>([^<]+)<\/h[1-6]><div\s+class="et_pb_toggle_content[^"]*"[^>]*>(.*?)<\/div>/is', $content, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (count($items) >= 10) break;

                    $question = wp_strip_all_tags(trim($match[1]));
                    $answer = wp_strip_all_tags(trim($match[2]));

                    if (!empty($question) && !empty($answer) && strlen($answer) > 5) {
                        $items[] = array(
                            '@type' => 'Question',
                            'name' => $question,
                            'acceptedAnswer' => array(
                                '@type' => 'Answer',
                                'text' => $answer
                            )
                        );
                    }
                }
            }
        }

        // Patroon 1b: Divi Toggle HTML - flexibeler met whitespace en andere attributen
        if (empty($items)) {
            if (preg_match_all('/<h[1-6][^>]*class="[^"]*et_pb_toggle_title[^"]*"[^>]*>(.*?)<\/h[1-6]>\s*<div[^>]*class="[^"]*et_pb_toggle_content[^"]*"[^>]*>(.*?)<\/div>/is', $content, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (count($items) >= 10) break;

                    $question = wp_strip_all_tags(trim($match[1]));
                    $answer = wp_strip_all_tags(trim($match[2]));

                    if (!empty($question) && !empty($answer) && strlen($answer) > 5) {
                        $items[] = array(
                            '@type' => 'Question',
                            'name' => $question,
                            'acceptedAnswer' => array(
                                '@type' => 'Answer',
                                'text' => $answer
                            )
                        );
                    }
                }
            }
        }

        // Patroon 1c: Divi Toggle HTML - zoek op class namen los van elkaar (meest flexibel)
        if (empty($items)) {
            if (preg_match_all('/et_pb_toggle_title[^>]*>([^<]+)<\/h[1-6]>.*?et_pb_toggle_content[^>]*>(.*?)<\/div>/is', $content, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (count($items) >= 10) break;

                    $question = wp_strip_all_tags(trim($match[1]));
                    $answer = wp_strip_all_tags(trim($match[2]));

                    if (!empty($question) && !empty($answer) && strlen($answer) > 5) {
                        $items[] = array(
                            '@type' => 'Question',
                            'name' => $question,
                            'acceptedAnswer' => array(
                                '@type' => 'Answer',
                                'text' => $answer
                            )
                        );
                    }
                }
            }
        }

        // Patroon 2: Elementor Accordion widgets
        if (empty($items)) {
            if (preg_match_all('/<[^>]*class="[^"]*elementor-tab-title[^"]*"[^>]*>(.*?)<\/[^>]+>\s*<[^>]*class="[^"]*elementor-tab-content[^"]*"[^>]*>(.*?)<\/div>/is', $content, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (count($items) >= 10) break;

                    $question = wp_strip_all_tags(trim($match[1]));
                    $answer = wp_strip_all_tags(trim($match[2]));

                    if (!empty($question) && !empty($answer) && strlen($answer) > 5) {
                        $items[] = array(
                            '@type' => 'Question',
                            'name' => $question,
                            'acceptedAnswer' => array(
                                '@type' => 'Answer',
                                'text' => $answer
                            )
                        );
                    }
                }
            }
        }

        // Patroon 3: H2/H3/H4 headings die eindigen met ?
        if (empty($items)) {
            if (preg_match_all('/<h[2-4][^>]*>([^<]*\?)<\/h[2-4]>/i', $content, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (count($items) >= 10) break;

                    $question = wp_strip_all_tags($match[1]);

                    // Zoek het antwoord (content tot de volgende heading)
                    $pos = strpos($content, $match[0]);
                    if ($pos !== false) {
                        $after_question = substr($content, $pos + strlen($match[0]));

                        // Haal content tot de volgende heading
                        if (preg_match('/^(.*?)(?=<h[1-6]|$)/is', $after_question, $answer_match)) {
                            $answer = wp_strip_all_tags($answer_match[1]);
                            $answer = trim($answer);

                            if (!empty($answer) && strlen($answer) > 10) {
                                $items[] = array(
                                    '@type' => 'Question',
                                    'name' => $question,
                                    'acceptedAnswer' => array(
                                        '@type' => 'Answer',
                                        'text' => $answer
                                    )
                                );
                            }
                        }
                    }
                }
            }
        }

        // Patroon 4: Zoek naar "Vraag:" / "Antwoord:" patronen
        if (empty($items)) {
            if (preg_match_all('/(?:vraag|question)[:\s]+([^<\n]+).*?(?:antwoord|answer)[:\s]+([^<\n]+)/is', $content, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    if (count($items) >= 10) break;

                    $question = wp_strip_all_tags(trim($match[1]));
                    $answer = wp_strip_all_tags(trim($match[2]));

                    if (!empty($question) && !empty($answer)) {
                        $items[] = array(
                            '@type' => 'Question',
                            'name' => $question,
                            'acceptedAnswer' => array(
                                '@type' => 'Answer',
                                'text' => $answer
                            )
                        );
                    }
                }
            }
        }

        // Als geen items gevonden, toon placeholder
        if (empty($items)) {
            $items[] = array(
                '@type' => 'Question',
                'name' => esc_html__( '[No FAQ questions found in content]', 'tam-rank' ),
                'acceptedAnswer' => array(
                    '@type' => 'Answer',
                    'text' => esc_html__( '[Add a Divi accordion, Elementor FAQ, or headings with question marks]', 'tam-rank' )
                )
            );
        }

        return $items;
    }

    /**
     * Extract HowTo steps from post content
     *
     * @param WP_Post $post Post object
     * @return array HowTo steps
     */
    private function extract_howto_steps($post) {
        $steps = array();
        $content = $post->post_content;

        // Nederlandse en Engelse nummer woorden mapping
        $nummer_woorden = array(
            'een' => 1, 'één' => 1, 'eerste' => 1,
            'twee' => 2, 'tweede' => 2,
            'drie' => 3, 'derde' => 3,
            'vier' => 4, 'vierde' => 4,
            'vijf' => 5, 'vijfde' => 5,
            'zes' => 6, 'zesde' => 6,
            'zeven' => 7, 'zevende' => 7,
            'acht' => 8, 'achtste' => 8,
            'negen' => 9, 'negende' => 9,
            'tien' => 10, 'tiende' => 10,
        );
        $woorden_pattern = implode( '|', array_keys( $nummer_woorden ) );

        // Strip HTML en normaliseer whitespace
        $plain_content = wp_strip_all_tags( $content );
        $plain_content = html_entity_decode( $plain_content, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
        $plain_content = preg_replace( '/\s+/', ' ', $plain_content );

        // METHODE 1: Zoek naar "Stap één:", "Stap twee:" etc. met nummer woorden
        if ( preg_match_all( '/(?:stap|step)\s+(' . $woorden_pattern . ')[\s:]+([^.!?]+)/iu', $plain_content, $matches, PREG_SET_ORDER ) ) {
            $gevonden_posities = array();
            foreach ( $matches as $match ) {
                $nummer_woord = mb_strtolower( trim( $match[1] ) );
                $position = isset( $nummer_woorden[ $nummer_woord ] ) ? $nummer_woorden[ $nummer_woord ] : 0;
                $step_text = trim( $match[2] );

                // Skip duplicaten
                if ( in_array( $position, $gevonden_posities, true ) ) {
                    continue;
                }

                if ( $position > 0 && ! empty( $step_text ) && strlen( $step_text ) > 3 ) {
                    $gevonden_posities[] = $position;
                    $steps[] = array(
                        '@type' => 'HowToStep',
                        'position' => $position,
                        'text' => $step_text
                    );
                }

                if ( count( $steps ) >= 10 ) break; // Max 10 stappen voor preview
            }
        }

        // METHODE 2: Zoek naar "Stap 1:", "Stap 2:" etc. met cijfers
        if ( empty( $steps ) && preg_match_all( '/(?:stap|step)\s*(\d+)[\s:]+([^.!?]+)/iu', $plain_content, $matches, PREG_SET_ORDER ) ) {
            foreach ( $matches as $match ) {
                $position = intval( $match[1] );
                $step_text = trim( $match[2] );

                if ( $position > 0 && ! empty( $step_text ) && strlen( $step_text ) > 3 ) {
                    $steps[] = array(
                        '@type' => 'HowToStep',
                        'position' => $position,
                        'text' => $step_text
                    );
                }

                if ( count( $steps ) >= 10 ) break;
            }
        }

        // METHODE 3: Zoek naar ordered list items
        if ( empty( $steps ) ) {
            preg_match_all('/<li>(.*?)<\/li>/is', $content, $matches);
            foreach ($matches[1] as $index => $step_text) {
                if ($index >= 10) break;
                $steps[] = array(
                    '@type' => 'HowToStep',
                    'position' => $index + 1,
                    'text' => wp_strip_all_tags($step_text)
                );
            }
        }

        // Sorteer op positie
        if ( ! empty( $steps ) ) {
            usort( $steps, function( $a, $b ) {
                return $a['position'] - $b['position'];
            });
        }

        // Als geen stappen gevonden, toon placeholder
        if (empty($steps)) {
            $steps[] = array(
                '@type' => 'HowToStep',
                'position' => 1,
                'text' => esc_html__( '[Step from content - detected automatically]', 'tam-rank' )
            );
        }

        return $steps;
    }

    /**
     * Extract video data from post content
     * Detecteert YouTube, Vimeo en HTML5 video's
     *
     * @param WP_Post $post Post object
     * @return array|null Video data met contentUrl, embedUrl, thumbnailUrl
     */
    private function extract_video_data($post) {
        $content = $post->post_content;

        // Zoek naar YouTube embeds
        if (preg_match('/(?:youtube\.com\/(?:embed\/|watch\?v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/', $content, $youtube_match)) {
            $video_id = $youtube_match[1];
            return array(
                'contentUrl' => 'https://www.youtube.com/watch?v=' . $video_id,
                'embedUrl' => 'https://www.youtube.com/embed/' . $video_id,
                'thumbnailUrl' => 'https://img.youtube.com/vi/' . $video_id . '/maxresdefault.jpg'
            );
        }

        // Zoek naar Vimeo embeds
        if (preg_match('/vimeo\.com\/(?:video\/)?(\d+)/', $content, $vimeo_match)) {
            $video_id = $vimeo_match[1];
            return array(
                'contentUrl' => 'https://vimeo.com/' . $video_id,
                'embedUrl' => 'https://player.vimeo.com/video/' . $video_id,
                'thumbnailUrl' => null // Vimeo vereist API voor thumbnail
            );
        }

        // Zoek naar HTML5 video tags
        if (preg_match('/<video[^>]*>.*?<source[^>]+src=["\']([^"\']+)["\'][^>]*>.*?<\/video>/is', $content, $video_match)) {
            return array(
                'contentUrl' => $video_match[1],
                'embedUrl' => null,
                'thumbnailUrl' => null
            );
        }

        // Zoek naar video shortcode of embed block met URL
        if (preg_match('/\[video[^\]]*src=["\']([^"\']+)["\'][^\]]*\]/', $content, $shortcode_match)) {
            return array(
                'contentUrl' => $shortcode_match[1],
                'embedUrl' => null,
                'thumbnailUrl' => null
            );
        }

        return null;
    }

    /**
     * Extract image data from post content
     *
     * @param WP_Post $post Post object
     * @return array|null Image data with url, width, height, caption
     */
    private function extract_image_data($post) {
        $content = $post->post_content;
        $post_id = $post->ID;

        // Eerst: probeer featured image (snelste optie)
        $thumbnail_id = get_post_thumbnail_id($post_id);
        if ($thumbnail_id) {
            $image_url = wp_get_attachment_image_url($thumbnail_id, 'full');
            $image_meta = wp_get_attachment_metadata($thumbnail_id);
            $caption = wp_get_attachment_caption($thumbnail_id);
            if ($image_url) {
                return array(
                    'url' => $image_url,
                    'width' => $image_meta['width'] ?? null,
                    'height' => $image_meta['height'] ?? null,
                    'caption' => $caption ?: null
                );
            }
        }

        // Zoek naar WordPress image blocks met attachment ID
        if (preg_match('/wp:image\s*\{"id":(\d+)[^}]*\}/', $content, $block_match)) {
            $attachment_id = intval($block_match[1]);
            $image_url = wp_get_attachment_url($attachment_id);
            if ($image_url) {
                $image_meta = wp_get_attachment_metadata($attachment_id);
                $caption = wp_get_attachment_caption($attachment_id);
                return array(
                    'url' => $image_url,
                    'width' => $image_meta['width'] ?? null,
                    'height' => $image_meta['height'] ?? null,
                    'caption' => $caption ?: null
                );
            }
        }

        // Zoek naar Divi image shortcodes [et_pb_image src="..."]
        if (preg_match('/\[et_pb_image[^\]]+src=["\']([^"\']+)["\'][^\]]*\]/is', $content, $divi_shortcode_match)) {
            return $this->build_image_result($divi_shortcode_match[1], $divi_shortcode_match[0]);
        }

        // Zoek naar Divi image modules in gerenderde HTML
        if (preg_match('/<div[^>]*class="[^"]*et_pb_image[^"]*"[^>]*>.*?<img[^>]+src=["\']([^"\']+)["\'][^>]*>/is', $content, $divi_match)) {
            return $this->build_image_result($divi_match[1], $content);
        }

        // Zoek naar img tags met src
        if (preg_match('/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', $content, $img_match)) {
            return $this->build_image_result($img_match[1], $img_match[0]);
        }

        // Zoek naar figure met wp-block-image class
        if (preg_match('/<figure[^>]*class="[^"]*wp-block-image[^"]*"[^>]*>.*?<img[^>]+src=["\']([^"\']+)["\'][^>]*>.*?(?:<figcaption[^>]*>([^<]*)<\/figcaption>)?/is', $content, $figure_match)) {
            $src = $figure_match[1];
            $caption = isset($figure_match[2]) ? trim($figure_match[2]) : null;

            $attachment_id = attachment_url_to_postid($src);
            if ($attachment_id) {
                $image_meta = wp_get_attachment_metadata($attachment_id);
                return array(
                    'url' => $src,
                    'width' => $image_meta['width'] ?? null,
                    'height' => $image_meta['height'] ?? null,
                    'caption' => $caption ?: wp_get_attachment_caption($attachment_id) ?: null
                );
            }

            return array(
                'url' => $src,
                'width' => null,
                'height' => null,
                'caption' => $caption
            );
        }

        return null;
    }

    /**
     * Build image result array from URL
     *
     * @param string $src Image URL
     * @param string $html_context HTML context to extract width/height/alt from
     * @return array Image data array
     */
    private function build_image_result($src, $html_context) {
        $width = null;
        $height = null;
        $alt = null;

        // Probeer width en height attributen te halen
        if (preg_match('/width=["\']?(\d+)["\']?/i', $html_context, $w_match)) {
            $width = intval($w_match[1]);
        }
        if (preg_match('/height=["\']?(\d+)["\']?/i', $html_context, $h_match)) {
            $height = intval($h_match[1]);
        }
        if (preg_match('/alt=["\']([^"\']*)["\']/', $html_context, $alt_match)) {
            $alt = $alt_match[1];
        }

        // Probeer attachment ID te vinden via URL
        $attachment_id = attachment_url_to_postid($src);
        if ($attachment_id) {
            $image_meta = wp_get_attachment_metadata($attachment_id);
            $caption = wp_get_attachment_caption($attachment_id);
            return array(
                'url' => $src,
                'width' => $image_meta['width'] ?? $width,
                'height' => $image_meta['height'] ?? $height,
                'caption' => $caption ?: $alt ?: null
            );
        }

        return array(
            'url' => $src,
            'width' => $width,
            'height' => $height,
            'caption' => $alt ?: null
        );
    }

    /**
     * Get field value for preview
     *
     * @param WP_Post $post Post object
     * @param array $mapping Field mapping configuration
     * @param TAMRANK_Schema_Settings $settings Settings instance
     * @return mixed Field value
     */
    private function get_preview_field_value($post, $mapping, $settings) {
        $source = $mapping['source'] ?? '';

        switch ($source) {
            case 'post_title':
                return get_the_title($post);

            case 'meta_description':
                return get_post_meta($post->ID, '_tam_rank_meta_description', true);

            case 'excerpt':
                return get_the_excerpt($post);

            case 'content_excerpt':
                $content = wp_strip_all_tags($post->post_content);
                return wp_trim_words($content, 30, '...');

            case 'featured_image':
                $thumbnail_id = get_post_thumbnail_id($post->ID);
                if ($thumbnail_id) {
                    $image_url = wp_get_attachment_image_url($thumbnail_id, 'full');
                    return array(
                        '@type' => 'ImageObject',
                        'url' => $image_url
                    );
                }
                return null;

            case 'author_name':
                return array(
                    '@type' => 'Person',
                    'name' => get_the_author_meta('display_name', $post->post_author),
                    'url' => get_author_posts_url($post->post_author)
                );

            case 'post_date':
                return get_the_date('c', $post);

            case 'post_modified':
                return get_the_modified_date('c', $post);

            case 'global_organization':
                return $settings->get_organization_schema();

            case 'manual':
                return $mapping['value'] ?? '';

            default:
                return null;
        }
    }

}
