<?php
/**
 * AI Citation Monitor — SearchShifter Authority (Dashboard UI)
 *
 * Tracks brand/domain mentions in ChatGPT, Gemini, and Perplexity.
 * Dashboard with charts + table + JSON inspector.
 *
 * Drop in to your plugin's includes and make sure it's loaded.
 */

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

if (! class_exists('SS_Citation_Monitor')):

class SS_Citation_Monitor {

    const DATA_DIR = WP_CONTENT_DIR . '/uploads/searchshifter/citations';
    const NONCE_ACTION = 'ss_citation_nonce';

    /** Initialize hooks */
    public static function init() {
        add_action('admin_menu', [__CLASS__, 'register_menu']);
        add_action('admin_enqueue_scripts', [__CLASS__, 'enqueue_admin_assets']);
        add_action('wp_ajax_ss_run_citation_scan', [__CLASS__, 'ajax_scan']);
        add_action('wp_ajax_ss_citation_stats', [__CLASS__, 'ajax_stats']);
        add_action('wp_ajax_ss_citation_clear', [__CLASS__, 'ajax_clear']);
        add_action('wp_ajax_ss_citation_get_evidence', [__CLASS__, 'ajax_get_evidence']);

        // ensure data dir is present
        register_activation_hook(SEARCHSHIFTER_BASENAME ?? __FILE__, [__CLASS__, 'maybe_create_tables']);
    }

    /** Register admin menu */
    public static function register_menu() {
        // Authority check (your plugin helper)
        $allowed = false;
        if (function_exists('ss_is_authority') && ss_is_authority()) {
            $allowed = true;
        }
        // fallback license check
        if (! $allowed && class_exists('SS_Licensing')) {
            try {
                $lic = SS_Licensing::get_cached_status();
                $plan = strtolower(trim($lic['plan'] ?? 'free'));
                if (in_array($plan, ['authority', 'elite'], true)) $allowed = true;
            } catch (Throwable $e) {}
        }

        if (! $allowed) {
            add_submenu_page(
                'searchshifter',
                __('AI Citation Monitor (Locked)','searchshifter'),
                __('AI Citation Monitor (🔒)','searchshifter'),
                'manage_options',
                'ss-citation-monitor-locked',
                function() {
                    echo '<div class="wrap"><h1>🔒 AI Citation Monitor</h1><p>This feature requires the <strong>Authority</strong> plan.</p></div>';
                }
            );
            return;
        }

        add_submenu_page(
            'searchshifter',
            __('AI Citation Monitor','searchshifter'),
            __('AI Citation Monitor','searchshifter'),
            'manage_options',
            'ss-citation-monitor',
            [__CLASS__, 'render_page']
        );
    }

    /** Enqueue admin scripts (Chart.js + styles + our script) */
    public static function enqueue_admin_assets($hook) {
        // only load on our plugin page
        if ($hook !== 'searchshifter_page_ss-citation-monitor' && $hook !== 'toplevel_page_searchshifter') {
            // the submenu generates page hook like searchshifter_page_ss-citation-monitor
            // We will also allow loading when plugin top-level page is used—safe skip otherwise.
            if (strpos($hook, 'ss-citation-monitor') === false) return;
        }

        // Chart.js from CDN
            wp_enqueue_script(
                'ss-chartjs',
                SEARCHSHIFTER_PLUGIN_URL . 'assets/js/chartjs/chart.umd.js',
                [],
                '4.4.0',
                true
            );

        // Our admin script
        wp_register_script('ss-citation-js', false, ['jquery','ss-chartjs'], SEARCHSHIFTER_VERSION ?? '1.0', true);
        wp_enqueue_script('ss-citation-js');

        // Inline JS because we didn't provide a local file — it's simpler for copy-paste installs.
        $nonce = wp_create_nonce(self::NONCE_ACTION);
        $ajax = admin_url('admin-ajax.php');
        
            $inline_js = "
                var ssCurrentPage = 1;
                var ssPerPage = 20;

                (function(\$){

                var ajaxurl = '{$ajax}';
                var nonce = '{$nonce}';

                function human(n){ return n === true ? 'Yes' : (n === false ? 'No' : String(n)); }

       

                function populateTable(results) {
                    var tbody = $('#ss_cite_table tbody');
                    tbody.empty();
                    results.forEach(function(r){
                        var chat = r.chatgpt || {};
                        var gem  = r.gemini || {};
                        var per  = r.perplexity || {};
                        var date = r.saved_at || '';
                        var row = '<tr data-id=\"'+(r.saved_id||0)+'\">' +
                            '<td style=\"vertical-align:middle;\"><strong>'+escapeHtml(r.term)+'</strong></td>' +
                            '<td>' + (
                                per.found
                                    ? ('✅ Detected (' + (per.confidence || 0) + '%)')
                                    : '❌ Not detected'
                            ) + '</td>' +

                            '<td>' + Math.max(
                                (chat.confidence || 0),
                                (gem.confidence || 0),
                                (per.confidence || 0)
                            ) + '%</td>' +
                            '<td><button class=\"button ss-view-evidence\" data-id=\"'+(r.saved_id||0)+'\">View</button></td>' +
                            '<td>' + escapeHtml(date) + '</td>' +
                            '</tr>';
                        tbody.append(row);
                    });
                }

                function escapeHtml(text) {
                    if (typeof text !== 'string') text = String(text);
                    return text
                        .replace(/&/g, '&amp;')
                        .replace(/</g, '&lt;')
                        .replace(/>/g, '&gt;')
                    
                        .replace(/'/g, '&#39;')
                        .replace(/\//g, '&#x2F;');
                }

                function renderEvidence(resp) {

                        var data = resp.data || resp;

                        var html = '';

                        html += '<div style=\"padding:15px;\">';

                        html += '<h2 style=\"margin-bottom:15px;\">AI Citation Evidence</h2>';

                        html += '<div style=\"margin-bottom:20px;\">';
                        html += '<strong>Tracked Term:</strong> ' + (data.term || '-') + '<br><br>';

                        // ChatGPT
                        if (data.chatgpt) {

                            html += '<div style=\"padding:12px;border:1px solid #ddd;border-radius:8px;margin-bottom:15px;\">';

                            html += '<h3>ChatGPT Analysis</h3>';

                            html += '<p><strong>Status:</strong> ' +
                                (data.chatgpt.found ? 'Detected ✅' : 'Not Detected ❌') +
                                '</p>';

                            html += '<p><strong>Confidence:</strong> ' +
                                (data.chatgpt.confidence || 0) + '%</p>';

                            if (data.chatgpt.summary) {
                                html += '<p><strong>Summary:</strong><br>' +
                                    data.chatgpt.summary + '</p>';
                            }

                            html += '</div>';
                        }

                        // Gemini
                        if (data.gemini) {

                            html += '<div style=\"padding:12px;border:1px solid #ddd;border-radius:8px;margin-bottom:15px;\">';

                            html += '<h3>Gemini Analysis</h3>';

                            html += '<p><strong>Status:</strong> ' +
                                (data.gemini.found ? 'Detected ✅' : 'Not Detected ❌') +
                                '</p>';

                            html += '<p><strong>Confidence:</strong> ' +
                                (data.gemini.confidence || 0) + '%</p>';

                            if (data.gemini.summary) {
                                html += '<p><strong>Summary:</strong><br>' +
                                    data.gemini.summary + '</p>';
                            }

                            html += '</div>';
                        }

                        // Perplexity
                        if (data.perplexity) {

                            html += '<div style=\"padding:12px;border:1px solid #ddd;border-radius:8px;\">';

                            html += '<h3>Perplexity Verified Citations</h3>';

                            html += '<p><strong>Status:</strong> ' +
                                (data.perplexity.found ? 'Verified ✅' : 'Not Found ❌') +
                                '</p>';

                            html += '<p><strong>Confidence:</strong> ' +
                                (data.perplexity.confidence || 0) + '%</p>';

                            var citations = data.perplexity.citations || [];

                            if (citations.length) {

                                html += '<h4>Verified Citation Sources</h4>';
                                html += '<ul>';

                                citations.forEach(function(c){
                                    html += '<li><a href=\"' + c + '\" target=\"_blank\">' + c + '</a></li>';
                                });

                                html += '</ul>';
                            }

                            html += '</div>';
                        }

                        html += '</div>';

                        return html;
                }

                function renderPagination(totalPages) {
                    var wrap = jQuery('#ss_cite_pagination');
                    wrap.empty();

                    if (!totalPages || totalPages <= 1) return;

                    var html = '';

                    if (ssCurrentPage > 1) {
                        html += '<button class=\"button ss-page-btn\" data-page=\"' + (ssCurrentPage - 1) + '\">‹ Prev</button>';
                    }

                    html += '<span style=\"margin:0 10px;\">Page ' + ssCurrentPage + ' of ' + totalPages + '</span>';

                    if (ssCurrentPage < totalPages) {
                        html += '<button class=\"button ss-page-btn\" data-page=\"' + (ssCurrentPage + 1) + '\">Next ›</button>';
                    }

                    wrap.html(html);
                }


                function updateCharts(results, totalFromServer) {
                    var counts = {
                        chat_found:0,
                        gem_found:0,
                        per_found:0,
                        total: totalFromServer || results.length
                    };


                    results.forEach(function(r){
                       
                        if (r.perplexity && r.perplexity.found) counts.per_found++;
                    });

                    /* -----------------------------
                    SUMMARY NUMBERS (NEW)
                    ----------------------------- */
                    if ($('#ss_sum_total').length) {
                        $('#ss_sum_total').text(counts.total);
                        $('#ss_sum_verified').text(counts.per_found);
                        $('#ss_sum_signal').text(counts.chat_found + counts.gem_found);
                    }

                    /* -----------------------------
                    PIE CHART
                    ----------------------------- */
                    var found = counts.per_found;
                    var notfound = counts.total - found;

                    window.ss_pie_data = [found, notfound];

                    if (window.ss_pie_chart) {
                        window.ss_pie_chart.data.datasets[0].data = window.ss_pie_data;
                        window.ss_pie_chart.update();
                    } else {
                        var ctx2 = document.getElementById('ss_chart_pie').getContext('2d');
                        window.ss_pie_chart = new Chart(ctx2, {
                            type: 'pie',
                            data: {
                                labels: ['Found','Not found'],
                                datasets: [{ data: window.ss_pie_data }]
                            },
                            options: { responsive:true }
                        });
                    }
                }


                function loadStatsAndPopulate() {
                    $.post(ajaxurl, {
                        action: 'ss_citation_stats',
                        _nonce: nonce,
                        page: ssCurrentPage,
                        per_page: ssPerPage
                    }, function(resp){
                        if (!resp) { $('#ss_cite_output').html('Empty response from stats endpoint.'); return; }
                        if (resp.success) {
                            var data = resp.data;
                            populateTable(data.results || []);
                            updateCharts(data.results || [], data.total || 0);
                            $('#ss_cite_output_json').text('');
                            renderPagination(data.total_pages || 1);
                            $('#ss_cite_output_json').html(renderUserFriendly(data));
                        } else {
                            $('#ss_cite_output_json').text('Error: ' + JSON.stringify(resp.data||resp));
                        }
                    }, 'json').fail(function(xhr){
                        $('#ss_cite_output_json').text('Stats request failed: ' + xhr.status + ' ' + xhr.statusText);
                    });
                }

                function renderUserFriendly(data) {

                    var html = '<div style=\'background:#fff;padding:15px;border-radius:8px;\'>';


                    if (!data.results || !data.results.length) {
                        html += '<p>No citation data available yet.</p>';
                    } else {

                        data.results.forEach(function (r) {

                            var found = r.perplexity && r.perplexity.found;
                            var confidence = (r.perplexity && r.perplexity.confidence)
                                ? r.perplexity.confidence
                                : 0;

                            html += '<div style=\'margin-bottom:12px;padding:10px;border:1px solid #eee;border-radius:6px;\'>';
                            html += '<strong>Term:</strong> ' + r.term + '<br>';
                            html += '<strong>Status:</strong> ' + (found ? 'Detected ✅' : 'Not Detected ❌') + '<br>';
                            html += '<strong>Confidence:</strong> ' + confidence + '%<br>';
                            html += '<strong>Last Scan:</strong> ' + (r.saved_at || '-') + '<br>';
                            html += '</div>';
                        });

                    }

                    html += '</div>';
                    return html;
                }


                $(document).on('click', '.ss-page-btn', function(){
                    var page = parseInt($(this).data('page'), 10);
                    if (!page || page === ssCurrentPage) return;

                    ssCurrentPage = page;
                    loadStatsAndPopulate();
                });

                

                $(document).on('click', '#ss_cite_scan', function(){

                    setScanningState(true);
                    $('#ss_cite_output_json').text(
                        'Scan started. Results will update automatically when ready…'
                    );

                    $.post(ajaxurl, {
                        action: 'ss_run_citation_scan',
                        _nonce: nonce
                    }, function(res){

                        if (!res) {
                            alert('Empty response from scan.');
                            return;
                        }

                        if (res.success) {

                            if (res.data && res.data.message) {
                                // already running case
                                $('#ss_cite_output_json').text(res.data.message);
                                return;
                            }

                            loadStatsAndPopulate();

                            setTimeout(function () {
                                loadStatsAndPopulate();
                            }, 8000);
                        } else {
                             loadStatsAndPopulate();
                        }

                    }, 'json')
                    .fail(function(xhr){
                        alert('Scan failed: ' + xhr.status + ' ' + xhr.statusText);
                    })
                    .always(function(){
                        setTimeout(function(){
                            setScanningState(false);
                        }, 5000); // prevent spam click
                    });

                });


                $(document).on('click', '#ss_cite_clear', function(){
                    if (!confirm('Clear stored citations and evidence files? This cannot be undone.')) return;
                    $.post(ajaxurl, { action: 'ss_citation_clear', _nonce: nonce }, function(resp){
                   if (resp && resp.success) {
                            alert('Cleared');

                            ssCurrentPage = 1;

                            // Reset UI immediately
                            $('#ss_cite_table tbody').empty();
                            $('#ss_cite_pagination').empty();
                            $('#ss_sum_total').text(0);
                            $('#ss_sum_verified').text(0);
                            $('#ss_sum_signal').text(0);

                            // Reset charts
                            if (window.ss_bar_chart) {
                                window.ss_bar_chart.data.datasets[0].data = [0,0,0];
                                window.ss_bar_chart.update();
                            }

                            if (window.ss_pie_chart) {
                                window.ss_pie_chart.data.datasets[0].data = [0,0];
                                window.ss_pie_chart.update();
                            }
                            loadStatsAndPopulate();
                        }
                            else {
                            alert('Clear failed: ' + JSON.stringify(resp));
                        }
                    }, 'json');
                });

                $(document).on('click', '#ss_cite_copy', function () {

                    var payload = [];

                    $('#ss_cite_table tbody tr').each(function(){
                        var cols = $(this).find('td');

                        payload.push({
                            term: cols.eq(0).text(),
                            status: cols.eq(1).text(),
                            confidence: cols.eq(2).text(),
                            date: cols.eq(4).text()
                        });
                    });

                    navigator.clipboard.writeText(
                        JSON.stringify(payload, null, 2)
                    ).then(
                        () => alert('Scan data copied to clipboard'),
                        () => alert('Copy failed')
                    );
                });


                $(document).on('click', '.ss-view-evidence', function(){
                    var id = $(this).data('id');
                    if (!id) return alert('No evidence for this row');
                    $.get(ajaxurl + '?action=ss_citation_get_evidence&_nonce=' + nonce + '&id=' + id, function(resp){
                        try {
                            var parsed = typeof resp === 'object' ? resp : JSON.parse(resp);
                            $('#ss_modal_content').html(renderEvidence(parsed));
                            $('#ss_modal').show();
                        } catch(e){
                            $('#ss_modal_content').text(String(resp));
                            $('#ss_modal').show();
                        }
                    }).fail(function(xhr){
                        $('#ss_modal_content').html(
                            '<p><strong>No evidence available yet.</strong></p>' +
                            '<p>Evidence files are generated only when a verified citation is found.</p>'
                        );
                        $('#ss_modal').show();
                    });
                });

                $(document).on('click', '#ss_modal_close', function(){ $('#ss_modal').hide(); });

                $(function(){
                    loadStatsAndPopulate();
                });

                function setScanningState(isScanning) {
                    var btn = $('#ss_cite_scan');

                    if (isScanning) {
                        btn.prop('disabled', true);
                        btn.data('orig-text', btn.text());
                        btn.text('Scanning… Please wait');
                        btn.addClass('button-disabled');
                    } else {
                        btn.prop('disabled', false);
                        btn.text(btn.data('orig-text') || 'Run Citation Scan');
                        btn.removeClass('button-disabled');
                    }
                }


            })(jQuery);";

        wp_add_inline_script('ss-citation-js', $inline_js);

        // Basic admin css for layout (small)
        $css = '
            #ss_citation_dashboard { display:flex; flex-direction:column; gap:18px; }
            #ss_citation_top {display:flex; gap:10px; align-items:center;}
            #ss_cite_charts { display:flex; gap:18px; align-items:flex-start; }
            #ss_cite_charts canvas { background:#fff; border-radius:6px; padding:6px; }
            #ss_cite_table { width:100%; border-collapse:collapse; }
            #ss_cite_table th, #ss_cite_table td { padding:8px 10px; border-bottom:1px solid #eee; }
            #ss_cite_output_json { background:#0b0b0b; color:#00ff66; padding:15px; border-radius:6px; min-height:300px; overflow:auto; }
            #ss_modal { position:fixed; top:10%; left:10%; right:10%; bottom:10%; background:#fff; border-radius:8px; z-index:99999; box-shadow:0 10px 30px rgba(0,0,0,0.5); display:none; padding:18px; overflow:auto; }
            #ss_modal_close { position:absolute; right:12px; top:8px; }
            #ss_cite_table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

#ss_cite_table th,
#ss_cite_table td {
    padding: 14px 12px;
    border-bottom: 1px solid #eee;
    vertical-align: middle;
}

#ss_cite_table th {
    text-align: left;
    font-weight: 600;
}

#ss_cite_table td:nth-child(1) {
    width: 24%;
}

#ss_cite_table td:nth-child(2) {
    width: 20%;
}

#ss_cite_table td:nth-child(3) {
    width: 16%;
    text-align: center;
}

#ss_cite_table td:nth-child(4) {
    width: 14%;
    text-align: center;
}

#ss_cite_table td:nth-child(5) {
    width: 26%;
    white-space: nowrap;
}

#ss_cite_table th:nth-child(3),
#ss_cite_table th:nth-child(4),
#ss_cite_table th:nth-child(5) {
    text-align: center;
}
        ';
        wp_register_style(
            'ss-citation-admin',
            false,
            [],
            defined( 'SEARCHSHIFTER_VERSION' ) ? SEARCHSHIFTER_VERSION : '1.0.0'
        );

        wp_enqueue_style('ss-citation-admin');
        wp_add_inline_style('ss-citation-admin', $css);

    }

    /** Render page HTML (dashboard layout) */
    public static function render_page() {
        // create data dir
        if (! file_exists(self::DATA_DIR)) {
            wp_mkdir_p(self::DATA_DIR);
        }
        ?>
        <div class="wrap">
            <h1><?php esc_html_e('AI Citation Monitor','searchshifter'); ?></h1>

            <div id="ss_citation_dashboard">
                <div id="ss_citation_top">
                    <p style="margin:0 8px 0 0;">
                        <?php esc_html_e('Tracks verified AI citations via Perplexity, with heuristic visibility signals for ChatGPT and Gemini.','searchshifter'); ?>
                    </p>
                    <button id="ss_cite_scan" class="button button-primary">Refresh Citation Scan</button>
                    <button id="ss_cite_clear" class="button">Clear Stored Data</button>
                    <button id="ss_cite_copy" class="button">Copy Output</button>
                </div>

                <div id="ss_cite_summary" style="display:flex;gap:16px;margin-bottom:12px;">
                    <div class="ss-box">
                        <strong>Total Tracked Terms</strong><br>
                        <span id="ss_sum_total">–</span><br>
                        <small style="color:#666;">
                            Unique brand & domain terms monitored (not scan runs)
                        </small>
                    </div>
                    <div class="ss-box">
                        <strong>Verified Mentions</strong><br>
                        <span id="ss_sum_verified">–</span>
                    </div>
                   
                </div>

                <style>
                    .ss-box{
                        background:#fff;
                        padding:12px 16px;
                        border-radius:8px;
                        box-shadow:0 1px 4px rgba(0,0,0,.08);
                        min-width:160px;
                    }
                </style>
    
                    <div id="ss_cite_charts" style="gap:24px;">
                    <div style="width:300px;">
                        <canvas id="ss_chart_pie" width="300" height="300"></canvas>
                    </div>

                    <div style="flex:1;">
                        <div id="ss_cite_pagination" style="margin-top:12px;"></div>
                        <table id="ss_cite_table">
                            <thead>
                                <tr>
                                    <th>Term</th>
                                    <th>Status</th>
                                    <th>AI Visibility Score</th>
                                    <th>Evidence</th>
                                    <th>Date</th>
                                </tr>
                            </thead>
                            <tbody>
                                <!-- rows filled by JS -->
                            </tbody>
                        </table>
                    </div>
                </div>

                <div style="margin-top:18px;">
                    <button class="button" id="ss_toggle_raw">Show Raw Data</button>
                    <br><br>
                    <div id="ss_cite_output_json" style="display:none;"></div>
                </div>
                <script>
                    jQuery(document).on('click','#ss_toggle_raw',function(){
                        var $box = jQuery('#ss_cite_output_json');
                        $box.toggle();
                        jQuery(this).text(
                            $box.is(':visible')
                                ? 'Hide Raw Data'
                                : 'Show Raw Data'
                        );
                    });
                </script>

            </div>
            
            <!-- Modal for evidence -->
            <div id="ss_modal" aria-hidden="true">
                <button id="ss_modal_close" class="button">Close</button>
                <div id="ss_modal_content" style="margin-top:20px;"></div>
            </div>

        </div>
        <?php
    }

    /** AJAX: Run Citation Scan */
    public static function ajax_scan() {
        // Clear stale scan lock (failsafe)
        $started = get_transient('ss_citation_scan_running_started');

        if ($started) {
            $age = time() - (int) $started;

            // If stuck > 3 minutes → auto clear
            if ($age > 180) {
                delete_transient('ss_citation_scan_running');
                delete_transient('ss_citation_scan_running_started');
            }
        }

        if (get_transient('ss_citation_scan_running')) {
            wp_send_json_success([
                'message' => 'Scan is already in progress. Please wait...'
            ]);
        }


        set_transient('ss_citation_scan_running', 1, 300);
        set_transient('ss_citation_scan_running_started', time(), 300);


        check_ajax_referer(self::NONCE_ACTION, '_nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(['error' => 'Insufficient permissions'], 403);
        }

        try {
            $result = self::run_scan();
            wp_send_json_success($result);
        } catch (Throwable $e) {
            wp_send_json_error(['error' => $e->getMessage()]);
        } finally {
            delete_transient('ss_citation_scan_running');
            delete_transient('ss_citation_scan_running_started');
        }

    }



    /** AJAX: Stats (summary + raw results) */
    public static function ajax_stats() {
        $ok = check_ajax_referer(self::NONCE_ACTION, '_nonce', false);
        if (! $ok) {
            wp_send_json_error(['error' => 'Invalid nonce'], 403);
        }
        if (! current_user_can('manage_options')) {
            wp_send_json_error(['error' => 'Insufficient permissions'], 403);
        }

        global $wpdb;

        $table = $wpdb->prefix . 'ss_citations';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $exists = $wpdb->get_var(
            $wpdb->prepare(
                'SHOW TABLES LIKE %s',
                $table
            )
        );

        if ( $exists !== $table ) {
            wp_send_json_success([
                'results'     => [],
                'total_pages' => 0,
                'page'        => 1,
            ]);
        }

        // ✅ pagination inputs
        $page     = max(1, intval($_POST['page'] ?? 1));
        $per_page = max(1, min(50, intval($_POST['per_page'] ?? 10)));
        $offset   = ($page - 1) * $per_page;

        // ✅ total rows
        // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $total = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$table}"
        );
        // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter

        $total_pages = max(1, (int) ceil($total / $per_page));

        // ✅ paginated query
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $rows = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT id, term, confidence, meta, found_at
                FROM {$table}
                ORDER BY id DESC
                LIMIT %d OFFSET %d",
                $per_page,
                $offset
            ),
            ARRAY_A
        );
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter



        $out = [];
        foreach ($rows as $r) {
            $meta = json_decode($r['meta'], true);
            $out[] = [
                'saved_id'   => (int) $r['id'],
                'term'       => $r['term'],
                'confidence' => (float) $r['confidence'],
                'chatgpt'    => $meta['chatgpt'] ?? null,
                'gemini'     => $meta['gemini'] ?? null,
                'perplexity' => $meta['perplexity'] ?? null,
                'saved_at'   => $r['found_at'] ?? null,
            ];
        }

        wp_send_json_success([
            'results'     => $out,
            'total'       => $total,
            'total_pages' => $total_pages,
            'page'        => $page,
        ]);
    }


    /** AJAX: Clear stored citations & evidence (admin only) */
    public static function ajax_clear() {

        check_ajax_referer(self::NONCE_ACTION, '_nonce');

        if (! current_user_can('manage_options')) {
            wp_send_json_error(['error' => 'Insufficient permissions'], 403);
        }

        global $wpdb;

        // 1️⃣ CLEAR ALL citation tables (NO CONDITIONS)
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $tables = $wpdb->get_col( "SHOW TABLES LIKE '%ss_citations%'" );
        $allowed_tables = [
            $wpdb->prefix . 'ss_citations'
        ];


        foreach ( $tables as $t ) {

            // Only allow known plugin tables
            if ( ! in_array( $t, $allowed_tables, true ) ) {
                continue;
            }

            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->query( "TRUNCATE TABLE `{$t}`" );

            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->query( "ALTER TABLE `{$t}` AUTO_INCREMENT = 1" );
        }



        // 2️⃣ Clear WP citation evidence
        self::rrmdir(self::DATA_DIR);
        wp_mkdir_p(self::DATA_DIR);

        // 3️⃣ Clear Authority evidence
        $domain = preg_replace('#^www\.#i', '', wp_parse_url(site_url(), PHP_URL_HOST));
        $authority_dir = WP_CONTENT_DIR . '/uploads/searchshifter/evidence/' . $domain;

        if (is_dir($authority_dir)) {
            self::rrmdir($authority_dir);
        }

        update_option('ss_citation_block_sync', 1, false);

        wp_send_json_success([
            'cleared' => true,
            'message' => 'All citation data and evidence cleared'
        ]);
    }




    /** Main scan. Returns structure with terms & results */
    public static function run_scan() {

        $block = (int) get_option('ss_citation_block_sync', 0);

        if ($block) {
            return [
                'ok' => true,
                'results' => []
            ];
        }

        // error_log('SCAN STARTED');

        $response = SS_API::authority_request('/api/authority/citation-scan', []);

        if (is_wp_error($response)) {
            // error_log('SCAN ERROR: ' . $response->get_error_message());
            throw new RuntimeException(
                esc_html($response->get_error_message())
            );
        }

        // error_log('SCAN RESPONSE: ' . print_r($response, true));

        if (empty($response['ok'])) {
            throw new RuntimeException(
                isset($response['error'])
                    ? esc_html($response['error'])
                    : 'Citation scan failed'
            );
        }

        $results = $response['results'] ?? [];

        foreach ($results as $entry) {
            self::save_result($entry['term'], $entry);
        }

        return $response;
    }

 
    /** Default brand terms (site name + domain + glossary) */
    public static function get_default_terms() {
        global $wpdb;

        $terms = [];

        $site_name = trim( get_bloginfo( 'name' ) ?: '' );
        if ( $site_name !== '' ) {
            $terms[] = $site_name;
        }

        $host = wp_parse_url( site_url(), PHP_URL_HOST );
        if ( $host ) {
            $terms[] = $host;
            $terms[] = preg_replace( '#^www\.#i', '', $host );
        }

        $table = $wpdb->prefix . 'ss_terms';

        // ---- Table existence check (prepare IS valid here) ----
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $exists = $wpdb->get_var(
            $wpdb->prepare(
                'SHOW TABLES LIKE %s',
                $table
            )
        );

        if ( $exists === $table ) {

            // ---- Read from custom table (identifiers cannot be prepared) ----
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $g = $wpdb->get_col(
                $wpdb->prepare(
                    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
                    "SELECT term_name FROM {$table} LIMIT %d",
                    10
                )
            );

            if ( $g ) {
                $terms = array_merge( $terms, $g );
            }
        }

        $terms = array_map( 'trim', $terms );
        $terms = array_filter(
            $terms,
            static function ( $v ) {
                return $v !== '';
            }
        );

        $terms = array_values( array_unique( $terms ) );

        if ( empty( $terms ) && $host ) {
            $terms[] = $host;
        }

        return $terms;
    }


    /** Query Perplexity (real) */



    /** Save record + evidence to DB + disk */
    private static function save_result($term, $entry) {
        global $wpdb;

        $table = $wpdb->prefix . 'ss_citations';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom table insert is required.
        $wpdb->insert(
            $table,
            [
                'term'       => mb_substr($term, 0, 255),
                'confidence' => intval($entry['perplexity']['confidence'] ?? 0),
                'meta'       => wp_json_encode($entry),
                'found_at'   => current_time('mysql'),
            ],
            ['%s','%d','%s','%s']
        );


        return (int) $wpdb->insert_id;
    }


    /** Create DB table(s) if missing */
    public static function maybe_create_tables() {
        global $wpdb;

        $table   = $wpdb->prefix . 'ss_citations';
        $charset = $wpdb->get_charset_collate();

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';

        $sql = "CREATE TABLE $table (
            id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
            term VARCHAR(255) NOT NULL,
            found_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            confidence FLOAT DEFAULT 0,
            meta LONGTEXT,
            PRIMARY KEY  (id)
        ) $charset;";

        dbDelta($sql);

        // ensure data dir
        if (! file_exists(self::DATA_DIR)) {
            wp_mkdir_p(self::DATA_DIR);
        }
    }


    /** Recursive delete - WP compliant */
    private static function rrmdir($dir) {

        if (! is_dir($dir)) {
            return false;
        }

        $files = scandir($dir);
        if (! $files) {
            return false;
        }

        foreach ($files as $file) {
            if ($file === '.' || $file === '..') {
                continue;
            }

            $full = trailingslashit($dir) . $file;

            if (is_dir($full)) {
                self::rrmdir($full);
            } else {
                wp_delete_file($full); // ✅ WP-approved
            }
        }

        // Remove the directory itself
        wp_rmdir($dir); // ✅ WP-approved

        return true;
    }

    public static function ajax_get_evidence() {

        check_ajax_referer(self::NONCE_ACTION, '_nonce');

        if (! current_user_can('manage_options')) {
            wp_send_json_error(['error' => 'Insufficient permissions'], 403);
        }

        global $wpdb;

        $id = isset($_GET['id']) ? absint($_GET['id']) : 0;

        if (!$id) {
            wp_send_json_error(['error' => 'Missing ID'], 400);
        }

        $cache_key = 'ss_citation_' . $id;
        $row = wp_cache_get($cache_key, 'searchshifter');

        if (false === $row) {

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            $row = $wpdb->get_row(
                $wpdb->prepare(
                    "SELECT meta FROM {$wpdb->prefix}ss_citations WHERE id = %d",
                    $id
                ),
                ARRAY_A
            );

            wp_cache_set($cache_key, $row, 'searchshifter', 300);
        }

        if (!$row) {
            wp_send_json_error(['error' => 'No data found'], 404);
        }

        $meta = json_decode($row['meta'], true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            wp_send_json_error(['error' => 'Invalid data format'], 500);
        }

        wp_send_json_success($meta);
    }

}

endif;

// initialize after plugins_loaded so licensing classes are available
add_action('plugins_loaded', function(){
    if (class_exists('SS_Citation_Monitor')) {
        SS_Citation_Monitor::init();
    } else {
        // load the class file if you placed it separately
    }
});
