<?php
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped,WordPress.Security.EscapeOutput.ExceptionNotEscaped,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQuery,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.WP.AlternativeFunctions.file_system_operations_fopen,WordPress.WP.AlternativeFunctions.file_system_operations_fclose,WordPress.WP.AlternativeFunctions.file_system_operations_is_writable,WordPress.WP.AlternativeFunctions.file_system_operations_chmod,WordPress.WP.AlternativeFunctions.file_system_operations_rmdir,WordPress.DateTime.RestrictedFunctions.date_date,WordPress.WP.I18n.NonSingularStringLiteralDomain,WordPress.WP.I18n.MissingTranslatorsComment,WordPress.WP.I18n.MissingArgDomain,WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters,WordPress.WP.EnqueuedResources.NonEnqueuedScript,WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet -- WordPress.org PCP audit pass: legacy controlled-beta surfaces require targeted follow-up hardening.
if (!defined('ABSPATH')) {
    exit;
}

$schema_project_id = intval(get_option('aysa_current_project_id', 0));
if (isset($this) && method_exists($this, 'aysa_technical_schema_resolve_project_id')) {
    $schema_project_id = $this->aysa_technical_schema_resolve_project_id($schema_project_id);
} elseif (isset($this) && method_exists($this, 'aysa_resolve_project_id_with_local_fallback')) {
    $schema_project_id = $this->aysa_resolve_project_id_with_local_fallback($schema_project_id);
}

$schema_v2_snapshot = array(
    'status' => 'idle',
    'summary' => array(
        'inventory_total' => 0,
        'google_eligible_total' => 0,
        'needs_action_total' => 0,
        'generated_total' => 0,
        'conflicts_total' => 0,
        'google_ready_total' => 0,
        'inventory_only_total' => 0,
        'entity_groups' => array(),
    ),
    'rows' => array(),
    'group_rows' => array(),
    'needs_reconcile' => true,
    'job' => null,
);

if ($schema_project_id > 0 && isset($this) && method_exists($this, 'aysa_schema_inventory_get_ui_snapshot')) {
    $snapshot = $this->aysa_schema_inventory_get_ui_snapshot($schema_project_id);
    if (is_array($snapshot)) {
        $schema_v2_snapshot = $snapshot;
    }
}

$schema_v2_snapshot['resolved_project_id'] = intval($schema_project_id);
?>
<div class="aysa-panel" id="aysa-schema-v2-root" data-project-id="<?php echo esc_attr($schema_project_id); ?>">
    <style>
        #aysa-schema-v2-root .aysa-schema-v2-toolbar {
            display: flex;
            justify-content: space-between;
            gap: 12px;
            align-items: flex-start;
            flex-wrap: wrap;
            margin-bottom: 14px;
        }
        #aysa-schema-v2-root .aysa-schema-v2-toolbar-actions,
        #aysa-schema-v2-root .aysa-schema-v2-bulk-actions,
        #aysa-schema-v2-root .aysa-schema-v2-filter-row {
            display: flex;
            gap: 8px;
            align-items: center;
            flex-wrap: wrap;
        }
        #aysa-schema-v2-root .aysa-schema-v2-summary {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 12px;
            margin: 14px 0 18px 0;
        }
        #aysa-schema-v2-root .aysa-schema-v2-card {
            background: #fff;
            border: 1px solid #dcdcde;
            border-radius: 10px;
            padding: 14px 16px;
        }
        #aysa-schema-v2-root .aysa-schema-v2-card-value {
            font-size: 24px;
            font-weight: 700;
            margin-top: 4px;
        }
        #aysa-schema-v2-root .aysa-schema-v2-chip {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            border: 1px solid #c3c4c7;
            background: #fff;
            border-radius: 999px;
            padding: 7px 12px;
            cursor: pointer;
            font-size: 13px;
        }
        #aysa-schema-v2-root .aysa-schema-v2-chip.is-active {
            background: #2271b1;
            color: #fff;
            border-color: #2271b1;
        }
        #aysa-schema-v2-root .aysa-schema-v2-chip-count {
            display: inline-flex;
            min-width: 22px;
            justify-content: center;
            padding: 1px 6px;
            border-radius: 999px;
            background: rgba(29, 35, 39, 0.08);
            font-size: 12px;
            font-weight: 600;
        }
        #aysa-schema-v2-root .aysa-schema-v2-chip.is-active .aysa-schema-v2-chip-count {
            background: rgba(255, 255, 255, 0.18);
        }
        #aysa-schema-v2-root .aysa-schema-v2-badge {
            display: inline-flex;
            align-items: center;
            padding: 3px 8px;
            border-radius: 999px;
            font-size: 12px;
            font-weight: 600;
            line-height: 1.3;
        }
        #aysa-schema-v2-root .aysa-schema-v2-badge.aysa-tone-neutral { background: #f0f0f1; color: #1d2327; }
        #aysa-schema-v2-root .aysa-schema-v2-badge.aysa-tone-blue { background: #eaf3ff; color: #135e96; }
        #aysa-schema-v2-root .aysa-schema-v2-badge.aysa-tone-green { background: #edfaef; color: #0a7d33; }
        #aysa-schema-v2-root .aysa-schema-v2-badge.aysa-tone-yellow { background: #fff3cd; color: #996800; }
        #aysa-schema-v2-root .aysa-schema-v2-badge.aysa-tone-red { background: #fbeaea; color: #b32d2e; }
        #aysa-schema-v2-root .aysa-schema-v2-table-wrap {
            border: 1px solid #dcdcde;
            border-radius: 10px;
            overflow: hidden;
            background: #fff;
        }
        #aysa-schema-v2-root .aysa-schema-v2-actions-col {
            white-space: nowrap;
        }
        #aysa-schema-v2-root .aysa-schema-v2-row {
            cursor: pointer;
        }
        #aysa-schema-v2-root .aysa-schema-v2-row:hover {
            background: #f6f7f7;
        }
        #aysa-schema-v2-root .aysa-schema-v2-drawer {
            position: fixed;
            inset: 0;
            z-index: 100001;
            display: none;
        }
        #aysa-schema-v2-root .aysa-schema-v2-drawer.is-open {
            display: block;
        }
        #aysa-schema-v2-root .aysa-schema-v2-drawer-backdrop {
            position: absolute;
            inset: 0;
            background: rgba(17, 24, 39, 0.45);
        }
        #aysa-schema-v2-root .aysa-schema-v2-drawer-panel {
            position: absolute;
            top: 0;
            right: 0;
            height: 100%;
            width: min(560px, 100%);
            background: #fff;
            box-shadow: -12px 0 40px rgba(0, 0, 0, 0.18);
            display: flex;
            flex-direction: column;
        }
        #aysa-schema-v2-root .aysa-schema-v2-drawer-header,
        #aysa-schema-v2-root .aysa-schema-v2-drawer-footer {
            padding: 18px 20px;
            border-bottom: 1px solid #dcdcde;
        }
        #aysa-schema-v2-root .aysa-schema-v2-drawer-footer {
            border-top: 1px solid #dcdcde;
            border-bottom: none;
            margin-top: auto;
        }
        #aysa-schema-v2-root .aysa-schema-v2-drawer-body {
            padding: 20px;
            overflow: auto;
        }
        #aysa-schema-v2-root .aysa-schema-v2-detail-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
            gap: 12px;
            margin: 14px 0 18px 0;
        }
        #aysa-schema-v2-root .aysa-schema-v2-detail-card {
            border: 1px solid #dcdcde;
            border-radius: 10px;
            padding: 12px 14px;
            background: #fff;
        }
        #aysa-schema-v2-root .aysa-schema-v2-list {
            margin: 0;
            padding-left: 18px;
        }
        #aysa-schema-v2-root .aysa-schema-v2-form-row {
            margin-bottom: 14px;
        }
        #aysa-schema-v2-root .aysa-schema-v2-form-row label {
            display: block;
            font-weight: 600;
            margin-bottom: 6px;
        }
        #aysa-schema-v2-root .aysa-schema-v2-empty {
            padding: 28px 22px;
            text-align: center;
            color: #646970;
        }
    </style>

    <div class="aysa-schema-v2-toolbar">
        <div>
            <h2 class="aysa-section-title">Schema Markup</h2>
            <p class="aysa-muted-note" style="margin:4px 0 0 0;">Single-page Google-first workspace for schema inventory, ownership, conflicts, automatic generation, and row-level exceptions.</p>
        </div>
        <div class="aysa-schema-v2-toolbar-actions">
            <button type="button" class="button" id="aysa-schema-v2-reconcile">Reconcile Inventory</button>
            <button type="button" class="button button-primary" id="aysa-schema-v2-auto-generate">Genereaza automat</button>
        </div>
    </div>

    <div id="aysa-schema-v2-status" class="notice inline" style="display:none;margin:0 0 12px 0;"><p></p></div>
    <div id="aysa-schema-v2-progress" style="display:none;margin:0 0 14px 0;padding:12px 14px;border:1px solid #dcdcde;border-radius:8px;background:#fff;">
        <div style="display:flex;justify-content:space-between;gap:12px;align-items:center;flex-wrap:wrap;">
            <div>
                <strong id="aysa-schema-v2-progress-label">Schema workspace idle</strong>
                <div id="aysa-schema-v2-progress-meta" class="description" style="margin-top:4px;">No active reconcile or generation job.</div>
            </div>
            <div id="aysa-schema-v2-progress-pill" class="aysa-schema-v2-badge aysa-tone-neutral">Idle</div>
        </div>
        <div style="margin-top:12px;height:10px;background:#f0f0f1;border-radius:999px;overflow:hidden;">
            <div id="aysa-schema-v2-progress-bar" style="width:0%;height:100%;background:linear-gradient(90deg,#2271b1 0%,#135e96 100%);transition:width .25s ease;"></div>
        </div>
    </div>

    <div id="aysa-schema-v2-summary" class="aysa-schema-v2-summary"></div>

    <div class="aysa-schema-v2-filter-row" id="aysa-schema-v2-filters" style="margin-bottom:14px;"></div>

    <div style="display:flex;justify-content:space-between;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:12px;">
        <div class="description" id="aysa-schema-v2-filter-description">All discovered entities in the DB-backed schema inventory.</div>
        <div class="aysa-schema-v2-bulk-actions">
            <button type="button" class="button" id="aysa-schema-v2-generate-selected">Generate selected</button>
            <button type="button" class="button" id="aysa-schema-v2-rewrite-selected">Rewrite selected</button>
            <button type="button" class="button" id="aysa-schema-v2-validate-selected">Validate selected</button>
        </div>
    </div>

    <div class="aysa-schema-v2-table-wrap">
        <div class="aysa-table-responsive">
            <table class="widefat striped" id="aysa-schema-v2-table">
                <thead>
                    <tr>
                        <th style="width:42px;"><input type="checkbox" id="aysa-schema-v2-select-all"></th>
                        <th>URL</th>
                        <th>Title</th>
                        <th>Entity</th>
                        <th>Google Policy</th>
                        <th>Ownership</th>
                        <th>Conflict</th>
                        <th>Generation</th>
                        <th>Readiness</th>
                        <th>Next Step</th>
                        <th>Last Checked</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </div>
    </div>

    <div class="aysa-schema-v2-drawer" id="aysa-schema-v2-drawer" aria-hidden="true">
        <div class="aysa-schema-v2-drawer-backdrop" data-drawer-close="1"></div>
        <div class="aysa-schema-v2-drawer-panel" role="dialog" aria-modal="true" aria-labelledby="aysa-schema-v2-drawer-title">
            <div class="aysa-schema-v2-drawer-header">
                <div style="display:flex;justify-content:space-between;gap:12px;align-items:flex-start;">
                    <div>
                        <h3 id="aysa-schema-v2-drawer-title" style="margin:0;">Schema row</h3>
                        <div id="aysa-schema-v2-drawer-subtitle" class="description" style="margin-top:4px;">Load a row to inspect policy, ownership, conflicts, and AYSA output.</div>
                    </div>
                    <button type="button" class="button" data-drawer-close="1">Close</button>
                </div>
            </div>
            <div class="aysa-schema-v2-drawer-body" id="aysa-schema-v2-drawer-body">
                <div class="aysa-schema-v2-empty">Select a row to inspect its Google policy and AYSA schema state.</div>
            </div>
            <div class="aysa-schema-v2-drawer-footer">
                <div style="display:flex;justify-content:space-between;gap:10px;align-items:center;flex-wrap:wrap;">
                    <div class="description" id="aysa-schema-v2-drawer-footer-status">Row-level actions run through the existing AYSA worker engine.</div>
                    <div class="aysa-schema-v2-bulk-actions">
                        <button type="button" class="button" id="aysa-schema-v2-drawer-generate">Generate</button>
                        <button type="button" class="button" id="aysa-schema-v2-drawer-rewrite">Rewrite</button>
                        <button type="button" class="button" id="aysa-schema-v2-drawer-validate">Validate</button>
                        <button type="button" class="button" id="aysa-schema-v2-drawer-disable">Disable AYSA</button>
                        <button type="button" class="button button-primary" id="aysa-schema-v2-drawer-save">Save settings</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script type="application/json" id="aysa-schema-v2-bootstrap"><?php echo wp_json_encode($schema_v2_snapshot); ?></script>
</div>

<script>
(function($) {
    const state = {
        filter: 'all',
        snapshot: null,
        selectedUrl: '',
        detail: null,
        runningJob: null
    };

    const FILTERS = [
        { key: 'all', label: 'All' },
        { key: 'google_eligible', label: 'Google Eligible' },
        { key: 'generated', label: 'Generated by AYSA' },
        { key: 'needs_action', label: 'Needs Action' },
        { key: 'conflict', label: 'Conflict' },
        { key: 'no_conflict', label: 'No Conflict' },
        { key: 'product', label: 'Products' },
        { key: 'article', label: 'Articles' },
        { key: 'ecommerce_category', label: 'Ecommerce Categories' },
        { key: 'business', label: 'Business' },
        { key: 'page', label: 'Normal Pages' }
    ];

    const FILTER_DESCRIPTIONS = {
        all: 'All discovered entities in the DB-backed schema inventory.',
        google_eligible: 'Rows with a strict Google Search policy and generation path in V2.',
        generated: 'Rows currently owned and generated by AYSA.',
        needs_action: 'Rows blocked by missing fields, conflicts, takeover, or validation issues.',
        conflict: 'Rows with mixed ownership or conflicting schema sources.',
        no_conflict: 'Rows without ownership conflicts.',
        product: 'WooCommerce product pages eligible for Product + Offer rich-result markup.',
        article: 'Editorial pages eligible for Article / BlogPosting markup.',
        ecommerce_category: 'Commerce category archives kept in inventory, with action only where policy allows.',
        business: 'Homepage and business-local pages using Organization/WebSite or LocalBusiness policy.',
        page: 'Generic pages kept in inventory. They are inventory-only unless explicitly mapped to a Google policy.'
    };

    function esc(value) {
        return $('<div>').text(String(value == null ? '' : value)).html();
    }

    function root() {
        return $('#aysa-schema-v2-root');
    }

    function projectId() {
        const $root = root();
        const raw = parseInt($root.attr('data-project-id') || $root.data('project-id') || 0, 10);
        if (!isNaN(raw) && raw > 0) {
            return raw;
        }
        return typeof getProjectId === 'function' ? getProjectId() : 0;
    }

    function setStatus(message, tone) {
        const $status = $('#aysa-schema-v2-status');
        if (!message) {
            $status.hide().removeClass('notice-error notice-warning notice-success notice-info');
            $status.find('p').text('');
            return;
        }
        const toneClass = tone === 'error'
            ? 'notice-error'
            : (tone === 'success' ? 'notice-success' : (tone === 'warning' ? 'notice-warning' : 'notice-info'));
        $status.removeClass('notice-error notice-warning notice-success notice-info').addClass(toneClass).show();
        $status.find('p').text(message);
    }

    function toneBadge(text, tone) {
        return '<span class="aysa-schema-v2-badge aysa-tone-' + esc(tone || 'neutral') + '">' + esc(text) + '</span>';
    }

    function formatLabel(value) {
        return String(value || '').replace(/_/g, ' ').replace(/\b\w/g, function(char) {
            return char.toUpperCase();
        });
    }

    function summarizeNextStep(row) {
        if (!parseInt(row.google_supported || 0, 10)) {
            return String(row.not_applicable_reason || 'Inventory only.');
        }
        if (parseInt(row.needs_takeover || 0, 10)) {
            return 'Rewrite to let AYSA replace the external source.';
        }
        if (String(row.google_readiness_status || '') === 'needs_fields') {
            const fields = Array.isArray(row.needs_fields) ? row.needs_fields : [];
            return fields.length ? ('Complete: ' + fields.join(', ')) : 'Complete required Google fields.';
        }
        if (parseInt(row.has_conflict || 0, 10)) {
            return 'Resolve conflict or let AYSA take over where allowed.';
        }
        if (parseInt(row.generated_by_aysa || 0, 10)) {
            return 'Validate frontend output and monitor Search Console.';
        }
        if (String(row.generation_status || '') === 'eligible') {
            return 'Safe to generate with AYSA.';
        }
        if (String(row.google_readiness_status || '') === 'ready') {
            return 'Already Google-ready.';
        }
        return 'Validate this row and inspect ownership.';
    }

    function rowMatchesFilter(row, filter) {
        switch (filter) {
            case 'google_eligible':
                return !!parseInt(row.google_supported || 0, 10);
            case 'generated':
                return !!parseInt(row.generated_by_aysa || 0, 10);
            case 'needs_action':
                return !!parseInt(row.google_supported || 0, 10) && (
                    !!parseInt(row.needs_takeover || 0, 10)
                    || ['needs_action', 'needs_fields', 'validation_failed'].includes(String(row.google_readiness_status || ''))
                    || ['needs_takeover', 'needs_fields', 'pending_validation'].includes(String(row.generation_status || ''))
                );
            case 'conflict':
                return !!parseInt(row.has_conflict || 0, 10);
            case 'no_conflict':
                return !parseInt(row.has_conflict || 0, 10);
            case 'page':
            case 'product':
            case 'ecommerce_category':
            case 'article':
            case 'business':
                return String(row.entity_group || 'page') === filter;
            case 'all':
            default:
                return true;
        }
    }

    function filteredRows(snapshot, filter) {
        const rows = Array.isArray(snapshot && snapshot.rows) ? snapshot.rows : [];
        return rows.filter(function(row) {
            return rowMatchesFilter(row, filter);
        });
    }

    function filterCounts(snapshot) {
        const counts = {};
        FILTERS.forEach(function(filter) {
            counts[filter.key] = filteredRows(snapshot, filter.key).length;
        });
        return counts;
    }

    function renderSummary(snapshot) {
        const summary = snapshot && snapshot.summary ? snapshot.summary : {};
        const cards = [
            ['Inventory', summary.inventory_total || 0],
            ['Google Eligible', summary.google_eligible_total || 0],
            ['Needs Action', summary.needs_action_total || 0],
            ['Generated by AYSA', summary.generated_total || 0],
            ['Conflicts', summary.conflicts_total || 0],
            ['Google Ready', summary.google_ready_total || 0]
        ];
        $('#aysa-schema-v2-summary').html(cards.map(function(card) {
            return '<div class="aysa-schema-v2-card">' +
                '<div class="description">' + esc(card[0]) + '</div>' +
                '<div class="aysa-schema-v2-card-value">' + parseInt(card[1] || 0, 10) + '</div>' +
            '</div>';
        }).join(''));
    }

    function renderFilters(snapshot) {
        const counts = filterCounts(snapshot);
        $('#aysa-schema-v2-filters').html(FILTERS.map(function(filter) {
            const active = filter.key === state.filter ? ' is-active' : '';
            return '<button type="button" class="aysa-schema-v2-chip' + active + '" data-filter="' + esc(filter.key) + '">' +
                '<span>' + esc(filter.label) + '</span>' +
                '<span class="aysa-schema-v2-chip-count">' + parseInt(counts[filter.key] || 0, 10) + '</span>' +
            '</button>';
        }).join(''));
        $('#aysa-schema-v2-filter-description').text(FILTER_DESCRIPTIONS[state.filter] || FILTER_DESCRIPTIONS.all);
    }

    function renderTable(snapshot) {
        const rows = filteredRows(snapshot, state.filter);
        const summaryGroups = snapshot && snapshot.summary && snapshot.summary.entity_groups ? snapshot.summary.entity_groups : {};
        const $tbody = $('#aysa-schema-v2-table tbody');
        if (!rows.length) {
            $tbody.html('<tr><td colspan="12" class="aysa-schema-v2-empty">No rows for this filter.</td></tr>');
            return;
        }

        $tbody.html(rows.map(function(row) {
            const url = String(row.url_normalized || '');
            const entityLabel = (summaryGroups[row.entity_group] && summaryGroups[row.entity_group].label) || formatLabel(row.entity_group || 'page');
            const ownership = String(row.ownership || 'none');
            const ownershipTone = ownership === 'aysa' ? 'green' : (ownership === 'external' ? 'yellow' : (ownership === 'mixed/conflict' ? 'red' : 'neutral'));
            const readiness = String(row.google_readiness_status || 'not_applicable');
            const readinessTone = readiness === 'ready' ? 'green' : (readiness === 'not_applicable' ? 'neutral' : (readiness === 'needs_fields' ? 'yellow' : 'red'));
            const generationTone = String(row.generation_status || '') === 'generated_by_aysa' ? 'green' : (String(row.generation_status || '') === 'eligible' ? 'blue' : 'yellow');
            const conflictTone = parseInt(row.has_conflict || 0, 10) ? 'red' : 'green';

            return '<tr class="aysa-schema-v2-row" data-url="' + esc(url) + '">' +
                '<td><input type="checkbox" class="aysa-schema-v2-row-select" data-url="' + esc(url) + '"></td>' +
                '<td><a href="' + esc(url) + '" target="_blank" rel="noopener noreferrer">' + esc(url) + '</a></td>' +
                '<td>' + esc(row.title || url) + '</td>' +
                '<td>' + esc(entityLabel) + '</td>' +
                '<td>' + esc(row.google_policy_type || 'generic_inventory_only') + '</td>' +
                '<td>' + toneBadge(formatLabel(ownership), ownershipTone) + '</td>' +
                '<td>' + toneBadge(parseInt(row.has_conflict || 0, 10) ? 'Yes' : 'No', conflictTone) + '</td>' +
                '<td>' + toneBadge(formatLabel(row.generation_status || 'inventory_only'), generationTone) + '</td>' +
                '<td>' + toneBadge(formatLabel(readiness), readinessTone) + '</td>' +
                '<td>' + esc(summarizeNextStep(row)) + '</td>' +
                '<td>' + esc(row.last_validated_at || '') + '</td>' +
                '<td class="aysa-schema-v2-actions-col">' +
                    '<button type="button" class="button button-small aysa-schema-v2-open" data-url="' + esc(url) + '">Open</button>' +
                '</td>' +
            '</tr>';
        }).join(''));
    }

    function render(snapshot) {
        state.snapshot = snapshot || {};
        renderSummary(state.snapshot);
        renderFilters(state.snapshot);
        renderTable(state.snapshot);
    }

    function selectedRows() {
        return $('#aysa-schema-v2-table tbody .aysa-schema-v2-row-select:checked').map(function() {
            return String($(this).data('url') || '');
        }).get().filter(Boolean);
    }

    function snapshotRowByUrl(url) {
        const normalized = String(url || '').trim();
        const rows = Array.isArray(state.snapshot && state.snapshot.rows) ? state.snapshot.rows : [];
        return rows.find(function(row) {
            return String(row.url_normalized || '') === normalized;
        }) || null;
    }

    function collectItems(urls) {
        return urls.map(function(url) {
            const row = snapshotRowByUrl(url);
            return row ? {
                url: String(row.url_normalized || ''),
                title: String(row.title || row.url_normalized || ''),
                page_family: String(row.page_family || 'page'),
                entity_group: String(row.entity_group || 'page'),
                schema_type: (function() {
                    const payload = row.payload_snapshot || {};
                    const legacy = payload.legacy_row || {};
                    if (legacy.primary_recommended_node) {
                        return String(legacy.primary_recommended_node);
                    }
                    const map = {
                        organization_website: 'organization',
                        local_business: 'localbusiness',
                        product_offer: 'product',
                        article: 'article',
                        faq_page: 'faqpage'
                    };
                    return String(map[row.google_policy_type] || 'webpage');
                })(),
                primary_recommended_node: ''
            } : null;
        }).filter(Boolean);
    }

    function setProgress(job, labelPrefix) {
        const total = Math.max(0, parseInt(job && job.total ? job.total : 0, 10) || 0);
        const processed = Math.max(0, parseInt(job && job.processed ? job.processed : 0, 10) || 0);
        const status = String(job && job.status ? job.status : 'idle');
        const percent = total > 0 ? Math.max(0, Math.min(100, Math.round((processed / total) * 100))) : 0;
        const tone = status === 'completed' ? 'green' : (status === 'failed' ? 'red' : (status === 'cancelled' ? 'yellow' : 'blue'));
        const labelMap = { queued: 'Queued', running: 'Running', completed: 'Completed', failed: 'Failed', cancelled: 'Cancelled', idle: 'Idle' };

        $('#aysa-schema-v2-progress').show();
        $('#aysa-schema-v2-progress-label').text(labelPrefix || 'Schema workspace job');
        $('#aysa-schema-v2-progress-meta').text(
            total > 0
                ? 'Job ' + (job.job_id || '') + ' · ' + processed + '/' + total + ' processed · ' + percent + '%'
                : 'Job ' + (job && job.job_id ? job.job_id : '')
        );
        $('#aysa-schema-v2-progress-bar').css('width', percent + '%');
        $('#aysa-schema-v2-progress-pill')
            .attr('class', 'aysa-schema-v2-badge aysa-tone-' + tone)
            .text(labelMap[status] || status);
    }

    async function pollJob(job, labelPrefix) {
        let currentJob = job;
        setProgress(currentJob, labelPrefix);
        while (currentJob && (currentJob.status === 'queued' || currentJob.status === 'running')) {
            await new Promise(function(resolve) { window.setTimeout(resolve, 1200); });
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_technical_schema_job_status',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: projectId(),
                    job_id: currentJob.job_id
                }
            });
            if (!(response && response.success && response.data && response.data.job)) {
                throw new Error((response && response.data) ? response.data : 'Schema job status failed.');
            }
            currentJob = response.data.job;
            setProgress(currentJob, labelPrefix);
        }
        return currentJob;
    }

    async function loadSnapshot() {
        const id = projectId();
        if (!id) {
            setStatus('Schema workspace could not resolve a project context.', 'error');
            return;
        }
        try {
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_schema_inventory_summary',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: id
                }
            });
            if (!(response && response.success && response.data && response.data.snapshot)) {
                throw new Error((response && response.data) ? response.data : 'Schema inventory could not be loaded.');
            }
            render(response.data.snapshot || {});
            if (response.data.snapshot && response.data.snapshot.needs_reconcile) {
                setStatus('Inventory is empty. Run Reconcile Inventory to populate the new Google-first workspace.', 'warning');
            } else {
                setStatus('', '');
            }
        } catch (error) {
            setStatus(error && error.message ? error.message : 'Schema inventory could not be loaded.', 'error');
        }
    }

    async function reconcileInventory() {
        const id = projectId();
        if (!id) {
            setStatus('Schema workspace could not resolve a project context.', 'error');
            return;
        }
        $('#aysa-schema-v2-reconcile').prop('disabled', true).text('Queueing...');
        setStatus('Queueing inventory reconcile...', 'info');
        try {
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_schema_reconcile_start',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: id
                }
            });
            if (!(response && response.success && response.data && response.data.job)) {
                throw new Error((response && response.data) ? response.data : 'Inventory reconcile could not start.');
            }
            let job = response.data.job;
            setProgress(job, 'Inventory reconcile');
            while (job && (job.status === 'queued' || job.status === 'running')) {
                await new Promise(function(resolve) { window.setTimeout(resolve, 1200); });
                const statusResponse = await $.ajax({
                    url: '<?php echo admin_url('admin-ajax.php'); ?>',
                    method: 'POST',
                    dataType: 'json',
                    data: {
                        action: 'aysa_schema_reconcile_status',
                        nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                        project_id: id,
                        job_id: job.job_id
                    }
                });
                if (!(statusResponse && statusResponse.success && statusResponse.data && statusResponse.data.job)) {
                    throw new Error((statusResponse && statusResponse.data) ? statusResponse.data : 'Inventory reconcile status failed.');
                }
                job = statusResponse.data.job;
                setProgress(job, 'Inventory reconcile');
            }
            if (job && job.status === 'completed') {
                setStatus('Inventory reconcile completed. Loading updated state...', 'success');
                await loadSnapshot();
            } else if (job && job.status === 'failed') {
                throw new Error(job.last_error || 'Inventory reconcile failed.');
            }
        } catch (error) {
            setStatus(error && error.message ? error.message : 'Inventory reconcile failed.', 'error');
        } finally {
            $('#aysa-schema-v2-reconcile').prop('disabled', false).text('Reconcile Inventory');
        }
    }

    async function runBulkAction(mode, buttonSelector, label) {
        const urls = selectedRows();
        if (!urls.length) {
            window.alert('Select at least one row.');
            return;
        }
        const items = collectItems(urls);
        if (!items.length) {
            window.alert('No valid rows were selected.');
            return;
        }
        const $button = $(buttonSelector);
        const original = $button.text();
        $button.prop('disabled', true).text('Queueing...');
        try {
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_technical_schema_job_start',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: projectId(),
                    mode: mode,
                    scope: 'selection',
                    items: JSON.stringify(items)
                }
            });
            if (!(response && response.success && response.data && response.data.job)) {
                throw new Error((response && response.data) ? response.data : 'Schema job could not be started.');
            }
            const finishedJob = await pollJob(response.data.job, label);
            if (finishedJob && finishedJob.status === 'completed') {
                setStatus(label + ' finished. Generated: ' + (finishedJob.generated || 0) + ', rewritten: ' + ((finishedJob.overwritten || 0) || (finishedJob.rewritten || 0)) + ', failed: ' + (finishedJob.failed || 0) + '.', 'success');
                await loadSnapshot();
            } else {
                throw new Error((finishedJob && finishedJob.last_error) || (label + ' failed.'));
            }
        } catch (error) {
            setStatus(error && error.message ? error.message : (label + ' failed.'), 'error');
        } finally {
            $button.prop('disabled', false).text(original);
        }
    }

    async function autoGenerate() {
        const $button = $('#aysa-schema-v2-auto-generate');
        const original = $button.text();
        $button.prop('disabled', true).text('Queueing...');
        try {
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_schema_inventory_auto_generate',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: projectId()
                }
            });
            if (!(response && response.success && response.data && response.data.job)) {
                throw new Error((response && response.data) ? response.data : 'Automatic generation could not be started.');
            }
            setStatus('Automatic generation queued for ' + parseInt(response.data.selected_count || 0, 10) + ' eligible row(s).', 'info');
            const finishedJob = await pollJob(response.data.job, 'Auto-generate');
            if (finishedJob && finishedJob.status === 'completed') {
                setStatus('Automatic generation completed. Generated: ' + (finishedJob.generated || 0) + ', rewritten: ' + ((finishedJob.overwritten || 0) || (finishedJob.rewritten || 0)) + ', needs fields: ' + (finishedJob.needs_fields || 0) + '.', 'success');
                await loadSnapshot();
            } else {
                throw new Error((finishedJob && finishedJob.last_error) || 'Automatic generation failed.');
            }
        } catch (error) {
            setStatus(error && error.message ? error.message : 'Automatic generation failed.', 'error');
        } finally {
            $button.prop('disabled', false).text(original);
        }
    }

    function closeDrawer() {
        $('#aysa-schema-v2-drawer').removeClass('is-open').attr('aria-hidden', 'true');
        state.selectedUrl = '';
        state.detail = null;
    }

    function renderDrawer(detail) {
        state.detail = detail || null;
        if (!detail) {
            $('#aysa-schema-v2-drawer-body').html('<div class="aysa-schema-v2-empty">Row details could not be loaded.</div>');
            return;
        }

        const identity = detail.identity || {};
        const policy = detail.policy || {};
        const validation = detail.validation || {};
        const schemas = detail.schemas || {};
        const rowState = detail.state || {};
        const overrides = policy.available_overrides || {};
        const overrideOptions = Object.keys(overrides).map(function(key) {
            const item = overrides[key] || {};
            const selected = String(rowState.policy_override || '') === String(key) ? ' selected' : '';
            return '<option value="' + esc(key) + '"' + selected + '>' + esc(item.label || key) + '</option>';
        }).join('');

        $('#aysa-schema-v2-drawer-title').text(identity.title || identity.url || 'Schema row');
        $('#aysa-schema-v2-drawer-subtitle').text(identity.url || '');
        $('#aysa-schema-v2-drawer-body').html(
            '<div class="aysa-schema-v2-detail-grid">' +
                '<div class="aysa-schema-v2-detail-card"><div class="description">Entity group</div><div><strong>' + esc(identity.entity_group_label || identity.entity_group || '') + '</strong></div></div>' +
                '<div class="aysa-schema-v2-detail-card"><div class="description">Page family</div><div><strong>' + esc(identity.page_family || '') + '</strong></div></div>' +
                '<div class="aysa-schema-v2-detail-card"><div class="description">Ownership</div><div><strong>' + esc(formatLabel(rowState.ownership || 'none')) + '</strong></div></div>' +
                '<div class="aysa-schema-v2-detail-card"><div class="description">Google policy</div><div><strong>' + esc(policy.google_policy_type || '') + '</strong></div></div>' +
                '<div class="aysa-schema-v2-detail-card"><div class="description">Generation</div><div><strong>' + esc(formatLabel(rowState.generation_status || '')) + '</strong></div></div>' +
                '<div class="aysa-schema-v2-detail-card"><div class="description">Readiness</div><div><strong>' + esc(formatLabel(rowState.google_readiness_status || '')) + '</strong></div></div>' +
            '</div>' +
            '<div class="postbox" style="margin:0 0 16px 0;"><div class="inside">' +
                '<h4 style="margin-top:0;">Google policy</h4>' +
                '<p class="description">Generation is strict Google-first. Generic pages stay inventory-only unless you deliberately override the policy.</p>' +
                '<p><strong>Required fields:</strong> ' + esc((policy.required_fields || []).join(', ') || 'None') + '</p>' +
                '<p><strong>Recommended fields:</strong> ' + esc((policy.recommended_fields || []).join(', ') || 'None') + '</p>' +
                (policy.not_applicable_reason ? '<p><strong>Reason:</strong> ' + esc(policy.not_applicable_reason) + '</p>' : '') +
            '</div></div>' +
            '<div class="postbox" style="margin:0 0 16px 0;"><div class="inside">' +
                '<h4 style="margin-top:0;">Validation and ownership</h4>' +
                '<p><strong>Conflict reason:</strong> ' + esc(rowState.conflict_reason || 'None') + '</p>' +
                '<p><strong>Missing fields:</strong> ' + esc((validation.needs_fields || []).join(', ') || 'None') + '</p>' +
                '<p><strong>Last checked:</strong> ' + esc(validation.last_checked || '—') + '</p>' +
                '<p><strong>Last generated by AYSA:</strong> ' + esc(validation.last_generated_at || '—') + '</p>' +
                '<p><strong>Last error:</strong> ' + esc(validation.last_error || '—') + '</p>' +
            '</div></div>' +
            '<div class="postbox" style="margin:0 0 16px 0;"><div class="inside">' +
                '<h4 style="margin-top:0;">Detected schemas</h4>' +
                '<p><strong>AYSA DB schema types:</strong> ' + esc((schemas.aysa_schema_types || []).join(', ') || 'None') + '</p>' +
                '<p><strong>Frontend detected types:</strong> ' + esc((schemas.frontend_detected_types || []).join(', ') || 'None') + '</p>' +
                '<div class="description">AYSA ownership markers are preserved in frontend output comments.</div>' +
            '</div></div>' +
            '<div class="postbox" style="margin:0;"><div class="inside">' +
                '<h4 style="margin-top:0;">Manual override</h4>' +
                '<div class="aysa-schema-v2-form-row">' +
                    '<label for="aysa-schema-v2-policy-override">Policy override</label>' +
                    '<select id="aysa-schema-v2-policy-override" class="regular-text">' +
                        '<option value="">Use detected policy</option>' +
                        overrideOptions +
                    '</select>' +
                '</div>' +
                '<div class="aysa-schema-v2-form-row">' +
                    '<label><input type="checkbox" id="aysa-schema-v2-inventory-only"' + (rowState.inventory_only_override ? ' checked' : '') + '> Force inventory-only for this row</label>' +
                '</div>' +
                '<p class="description">This is the only manual edit in V2: override the policy or keep the row out of auto-generation. No JSON editing is exposed here.</p>' +
            '</div></div>'
        );

        $('#aysa-schema-v2-drawer-footer-status').text('Selected URL: ' + (identity.url || ''));
        const actions = Array.isArray(detail.available_actions) ? detail.available_actions : [];
        $('#aysa-schema-v2-drawer-generate').prop('disabled', actions.indexOf('generate') === -1);
        $('#aysa-schema-v2-drawer-rewrite').prop('disabled', actions.indexOf('rewrite') === -1);
        $('#aysa-schema-v2-drawer-validate').prop('disabled', actions.indexOf('validate') === -1);
        $('#aysa-schema-v2-drawer-disable').prop('disabled', actions.indexOf('disable') === -1);
    }

    async function openDrawer(url) {
        state.selectedUrl = String(url || '').trim();
        if (!state.selectedUrl) {
            return;
        }
        $('#aysa-schema-v2-drawer').addClass('is-open').attr('aria-hidden', 'false');
        $('#aysa-schema-v2-drawer-body').html('<div class="aysa-schema-v2-empty">Loading row details...</div>');
        try {
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_schema_inventory_detail',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: projectId(),
                    url: state.selectedUrl
                }
            });
            if (!(response && response.success && response.data && response.data.detail)) {
                throw new Error((response && response.data) ? response.data : 'Row detail could not be loaded.');
            }
            renderDrawer(response.data.detail);
        } catch (error) {
            $('#aysa-schema-v2-drawer-body').html('<div class="aysa-schema-v2-empty">' + esc(error && error.message ? error.message : 'Row detail could not be loaded.') + '</div>');
        }
    }

    async function runRowAction(actionName) {
        if (!state.selectedUrl) {
            return;
        }
        const buttonMap = {
            generate: '#aysa-schema-v2-drawer-generate',
            rewrite: '#aysa-schema-v2-drawer-rewrite',
            validate: '#aysa-schema-v2-drawer-validate',
            disable: '#aysa-schema-v2-drawer-disable'
        };
        const labels = {
            generate: 'Generate',
            rewrite: 'Rewrite',
            validate: 'Validate',
            disable: 'Disable AYSA'
        };
        const $button = $(buttonMap[actionName]);
        const original = $button.text();
        $button.prop('disabled', true).text('Queueing...');
        try {
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_schema_inventory_row_action',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: projectId(),
                    url: state.selectedUrl,
                    row_action: actionName
                }
            });
            if (!(response && response.success && response.data && response.data.job)) {
                throw new Error((response && response.data) ? response.data : 'Row action could not be started.');
            }
            const finishedJob = await pollJob(response.data.job, labels[actionName] || 'Schema row action');
            if (finishedJob && finishedJob.status === 'completed') {
                setStatus((labels[actionName] || 'Action') + ' completed for the selected row.', 'success');
                await loadSnapshot();
                await openDrawer(state.selectedUrl);
            } else {
                throw new Error((finishedJob && finishedJob.last_error) || 'Row action failed.');
            }
        } catch (error) {
            setStatus(error && error.message ? error.message : 'Row action failed.', 'error');
        } finally {
            $button.prop('disabled', false).text(original);
        }
    }

    async function saveDrawerSettings() {
        if (!state.selectedUrl) {
            return;
        }
        const $button = $('#aysa-schema-v2-drawer-save');
        const original = $button.text();
        $button.prop('disabled', true).text('Saving...');
        try {
            const response = await $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                method: 'POST',
                dataType: 'json',
                data: {
                    action: 'aysa_schema_inventory_row_update',
                    nonce: '<?php echo wp_create_nonce('aysa_technical_audit_nonce'); ?>',
                    project_id: projectId(),
                    url: state.selectedUrl,
                    policy_override: $('#aysa-schema-v2-policy-override').val() || '',
                    inventory_only: $('#aysa-schema-v2-inventory-only').is(':checked') ? 1 : 0
                }
            });
            if (!(response && response.success && response.data && response.data.detail)) {
                throw new Error((response && response.data) ? response.data : 'Row settings could not be saved.');
            }
            renderDrawer(response.data.detail);
            setStatus('Row settings saved. The inventory row was recalculated with the updated policy override.', 'success');
            await loadSnapshot();
        } catch (error) {
            setStatus(error && error.message ? error.message : 'Row settings could not be saved.', 'error');
        } finally {
            $button.prop('disabled', false).text(original);
        }
    }

    $(document).on('click', '#aysa-schema-v2-filters .aysa-schema-v2-chip', function() {
        state.filter = String($(this).data('filter') || 'all');
        render(state.snapshot || {});
    });

    $(document).on('change', '#aysa-schema-v2-select-all', function() {
        $('#aysa-schema-v2-table tbody .aysa-schema-v2-row-select').prop('checked', $(this).is(':checked'));
    });

    $(document).on('click', '#aysa-schema-v2-reconcile', function(e) {
        e.preventDefault();
        reconcileInventory();
    });

    $(document).on('click', '#aysa-schema-v2-auto-generate', function(e) {
        e.preventDefault();
        autoGenerate();
    });

    $(document).on('click', '#aysa-schema-v2-generate-selected', function(e) {
        e.preventDefault();
        runBulkAction('generate_safe', '#aysa-schema-v2-generate-selected', 'Generate selected');
    });

    $(document).on('click', '#aysa-schema-v2-rewrite-selected', function(e) {
        e.preventDefault();
        runBulkAction('rewrite_recommended', '#aysa-schema-v2-rewrite-selected', 'Rewrite selected');
    });

    $(document).on('click', '#aysa-schema-v2-validate-selected', function(e) {
        e.preventDefault();
        runBulkAction('validate', '#aysa-schema-v2-validate-selected', 'Validate selected');
    });

    $(document).on('click', '#aysa-schema-v2-table .aysa-schema-v2-open', function(e) {
        e.preventDefault();
        e.stopPropagation();
        openDrawer($(this).data('url'));
    });

    $(document).on('click', '#aysa-schema-v2-table tbody tr.aysa-schema-v2-row', function(e) {
        if ($(e.target).is('input, button, a, label')) {
            return;
        }
        openDrawer($(this).data('url'));
    });

    $(document).on('click', '[data-drawer-close="1"]', function(e) {
        e.preventDefault();
        closeDrawer();
    });

    $(document).on('click', '#aysa-schema-v2-drawer-generate', function(e) {
        e.preventDefault();
        runRowAction('generate');
    });

    $(document).on('click', '#aysa-schema-v2-drawer-rewrite', function(e) {
        e.preventDefault();
        runRowAction('rewrite');
    });

    $(document).on('click', '#aysa-schema-v2-drawer-validate', function(e) {
        e.preventDefault();
        runRowAction('validate');
    });

    $(document).on('click', '#aysa-schema-v2-drawer-disable', function(e) {
        e.preventDefault();
        runRowAction('disable');
    });

    $(document).on('click', '#aysa-schema-v2-drawer-save', function(e) {
        e.preventDefault();
        saveDrawerSettings();
    });

    document.addEventListener('DOMContentLoaded', function() {
        const bootstrapNode = document.getElementById('aysa-schema-v2-bootstrap');
        if (!bootstrapNode) {
            return;
        }
        try {
            const snapshot = JSON.parse(bootstrapNode.textContent || '{}');
            render(snapshot);
            if (!snapshot || !Array.isArray(snapshot.rows) || !snapshot.rows.length) {
                setStatus('Inventory is empty. Run Reconcile Inventory to build the DB-backed schema workspace.', 'warning');
            }
        } catch (error) {
            console.error('Failed to bootstrap schema V2 workspace', error);
            setStatus('Schema workspace bootstrap failed. Run Reconcile Inventory to rebuild the DB-backed state.', 'error');
        }
        loadSnapshot();
    });
})(jQuery);
</script>
