<?php
/**
 * firefly-seo.php (Theme file)
 *
 * Firefly SEO report (Customizer section + preview overlay report)
 *
 * Score out of 5 (1 point each):
 *  1) Page title is meaningful (not generic like Home/Contact/etc)
 *  2) URL slug is meaningful (not generic like about-us/contact-us/etc)
 *  3) Page has a meaningful H1 (exists + not generic)
 *  4) Keyword/phrase appears in body text (excluding H1) (fuzzy match)
 *  5) Keyword/phrase appears in any image ALT text on that page (fuzzy match)
 *
 * Generic pages (e.g. Contact/Home/About/etc) are excluded from optimisation scoring:
 *  - Score forced to 0/5
 *  - Not included in the summary list
 *
 * Load from functions.php:
 *   require_once get_template_directory() . '/firefly-seo.php';
 */

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

/* ------------------------------------------------------------
 *  1) Customizer section (menu item)
 * ------------------------------------------------------------ */
add_action('customize_register', function($wp_customize){

    $wp_customize->add_section('firefly_seo_report_section', [
        'title'       => __('Firefly SEO report', 'firefly'),
        'priority'    => 35,
        'description' => __('Open this section to display an SEO report in the preview window.', 'firefly'),
    ]);

    // Dummy control so the section isn't empty
    $wp_customize->add_setting('firefly_seo_report_dummy', [
        'default'           => '',
        'sanitize_callback' => 'sanitize_text_field',
    ]);

    $wp_customize->add_control('firefly_seo_report_dummy', [
        'label'       => __('SEO report', 'firefly'),
        'description' => __('When this panel is open, the preview shows a table of URLs, titles, H1 presence, keyword checks, scoring, and alerts.', 'firefly'),
        'section'     => 'firefly_seo_report_section',
        'type'        => 'hidden',
    ]);
});

/* ------------------------------------------------------------
 *  2) Controls-side JS: when section opens/closes, tell preview
 * ------------------------------------------------------------ */
add_action('customize_controls_enqueue_scripts', function () {

    wp_add_inline_script('customize-controls', '
        (function(wp){
            if (!wp || !wp.customize) return;

            function send(enabled){
                try {
                    wp.customize.previewer.send("firefly_seo_report_toggle", { enabled: !!enabled });
                } catch(e) {}
            }

            wp.customize.bind("ready", function(){
                wp.customize.section("firefly_seo_report_section", function(section){

                    // If already open when binding, trigger immediately
                    if (section.expanded && section.expanded()) {
                        send(true);
                    }

                    section.expanded.bind(function(isExpanded){
                        send(!!isExpanded);
                    });
                });
            });

        })(window.wp);
    ');
});

/* ------------------------------------------------------------
 *  3) Preview-side JS/CSS: listen for toggle, overlay report
 * ------------------------------------------------------------ */
add_action('customize_preview_init', function () {

    if (!is_customize_preview()) return;

    wp_enqueue_script('customize-preview');

    $nonce = wp_create_nonce('firefly_seo_report');

    wp_add_inline_script('customize-preview', '
        (function(wp){
            if (!wp || !wp.customize) return;

            var overlayId = "firefly-seo-report-overlay";
            var cssId     = "firefly-seo-report-css";
            var isOn      = false;
            var loading   = false;

            function ensureCss(){
                if (document.getElementById(cssId)) return;
                var style = document.createElement("style");
                style.id = cssId;
                style.textContent = `
                    body.firefly-seo-report-on > *:not(#${overlayId}) { display:none !important; }
                    body.firefly-seo-report-on {
                        margin:0 !important;
                        background:#fff !important;
                        color:#111 !important;
                        font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif !important;
                    }
                    #${overlayId}{
                        display:block;
                        background:#fff;
                        min-height:100vh;
                        padding:22px 26px;
                        box-sizing:border-box;
                    }
                    #${overlayId} .wrap{ max-width:1500px; margin:0 auto; }
                    #${overlayId} h1{ margin:0 0 6px 0; font-size:18px; font-weight:700; }
                    #${overlayId} .sub{ margin:0 0 16px 0; font-size:13px; color:#555; }

                    #${overlayId} table{
                        width:100%;
                        border-collapse:collapse;
                        border:1px solid #e6e6e6;
                        border-radius:10px;
                        overflow:hidden;
                    }
                    #${overlayId} thead th{
                        background:#f6f6f6;
                        text-align:left;
                        padding:10px 12px;
                        font-size:12px;
                        text-transform:uppercase;
                        letter-spacing:.04em;
                        border-bottom:1px solid #e6e6e6;
                        color:#333;
                        vertical-align:bottom;
                    }
                    #${overlayId} tbody td{
                        padding:10px 12px;
                        border-bottom:1px solid #f0f0f0;
                        vertical-align:top;
                        font-size:13px;
                        line-height:1.35;
                    }
                    #${overlayId} tbody tr:hover td{ background:#fafafa; }
                    #${overlayId} a{ color:#0b57d0; text-decoration:none; word-break:break-all; }
                    #${overlayId} a:hover{ text-decoration:underline; }
                    #${overlayId} .muted{ color:#777; font-size:12px; }

                    #${overlayId} .ff-bad{ color:#b00020; font-weight:700; }
                    #${overlayId} .ff-good{ color:#0a6b2b; font-weight:700; }

                    #${overlayId} .ff-pill{
                        display:inline-block;
                        padding:3px 8px;
                        border-radius:999px;
                        font-size:12px;
                        border:1px solid rgba(0,0,0,.10);
                        background: rgba(0,0,0,.03);
                        color:#333;
                        margin-right:6px;
                        margin-bottom:4px;
                    }
                    #${overlayId} .ff-warn{
                        display:inline-block;
                        padding:3px 8px;
                        border-radius:999px;
                        font-size:12px;
                        border:1px solid rgba(176,0,32,.25);
                        background: rgba(176,0,32,.06);
                        color:#b00020;
                        margin-right:6px;
                        margin-bottom:4px;
                    }
                    #${overlayId} .ff-score{
                        display:inline-flex;
                        align-items:center;
                        gap:8px;
                        padding:4px 10px;
                        border-radius:999px;
                        font-size:12px;
                        border:1px solid rgba(10,107,43,.25);
                        background: rgba(10,107,43,.06);
                        color:#0a6b2b;
                        margin-top:6px;
                    }
                    #${overlayId} .ff-stars{
                        font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
                        letter-spacing: 1px;
                        white-space:nowrap;
                    }

                    #${overlayId} .ff-summary{
                        margin-top:18px;
                        border:1px solid #e6e6e6;
                        border-radius:10px;
                        padding:14px 16px;
                        background:#fff;
                    }
                    #${overlayId} .ff-summary h2{
                        margin:0 0 8px 0;
                        font-size:14px;
                        font-weight:700;
                    }
                    #${overlayId} .ff-summary .line{
                        display:flex;
                        align-items:center;
                        gap:10px;
                        font-size:13px;
                        margin:6px 0;
                    }
                    #${overlayId} .ff-summary .phrase{
                        min-width: 260px;
                    }
                    #${overlayId} .ff-summary .score{
                        color:#0a6b2b;
                        font-weight:700;
                        white-space:nowrap;
                    }
                `;
                document.head.appendChild(style);
            }

            function ensureOverlay(){
                var el = document.getElementById(overlayId);
                if (el) return el;
                el = document.createElement("div");
                el.id = overlayId;
                el.innerHTML = `<div class="wrap">
                    <h1>Firefly SEO report</h1>
                    <p class="sub">Loading…</p>
                </div>`;
                document.body.appendChild(el);
                return el;
            }

            function fetchReport(){
                if (loading) return;
                loading = true;

                var el = ensureOverlay();
                var sub = el.querySelector(".sub");
                if (sub) sub.textContent = "Loading…";

                var data = new FormData();
                data.append("action", "firefly_seo_report_html");
                data.append("nonce", ' . json_encode($nonce) . ');

                fetch(' . json_encode(admin_url('admin-ajax.php')) . ', {
                    method: "POST",
                    credentials: "same-origin",
                    body: data
                })
                .then(function(r){ return r.text(); })
                .then(function(html){
                    el.innerHTML = html;
                    loading = false;
                })
                .catch(function(){
                    if (sub) sub.textContent = "Failed to load report.";
                    loading = false;
                });
            }

            function turnOn(){
                if (isOn) return;
                isOn = true;
                ensureCss();
                ensureOverlay();
                document.body.classList.add("firefly-seo-report-on");
                fetchReport();
            }

            function turnOff(){
                if (!isOn) return;
                isOn = false;
                document.body.classList.remove("firefly-seo-report-on");
            }

            wp.customize.bind("preview-ready", function(){
                wp.customize.preview.bind("firefly_seo_report_toggle", function(msg){
                    if (msg && msg.enabled) turnOn();
                    else turnOff();
                });
            });

        })(window.wp);
    ');
});

/* ------------------------------------------------------------
 *  4) AJAX: generate report HTML (server-side)
 * ------------------------------------------------------------ */
add_action('wp_ajax_firefly_seo_report_html', function () {

    if (!current_user_can('customize')) {
        status_header(403);
        echo 'Forbidden';
        wp_die();
    }

    $nonce = isset($_POST['nonce']) ? (string)$_POST['nonce'] : '';
    if (!wp_verify_nonce($nonce, 'firefly_seo_report')) {
        status_header(403);
        echo 'Bad nonce';
        wp_die();
    }

    $pages = get_posts([
        'post_type'              => 'page',
        'post_status'            => 'publish',
        'posts_per_page'         => -1,
        'orderby'                => 'menu_order',
        'order'                  => 'ASC',
        'no_found_rows'          => true,
        'update_post_meta_cache' => false,
        'update_post_term_cache' => false,
    ]);

    $front_id = (int) get_option('page_on_front');

    // Generic slugs we want to discourage (editable list)
    $generic_slugs = [
        'home','homepage',
        'about','about-us','aboutus',
        'contact','contact-us','contactus',
        'products','product','services','service',
        'blog','news','events',
        'gallery','portfolio',
        'shop','store',
        'faq','help',
        'privacy','privacy-policy',
        'terms','terms-and-conditions',
        'sample-page',
    ];

    // Stopwords to ignore when building fuzzy keyword tokens
    $stopwords = [
        'a','an','and','are','as','at','be','but','by',
        'for','from','has','have','he','her','his','how',
        'i','if','in','into','is','it','its',
        'just','like','love','me','my',
        'of','on','or','our','she','so','that','the','their','them','then','there','these','they','this','those','to','us',
        'was','we','were','what','when','where','who','why','with','you','your','all'
    ];

    $normalize = function(string $s): string {
        $s = strtolower(trim($s));
        $s = preg_replace('/\s+/', ' ', $s);
        return $s;
    };

    $is_generic_slug = function(string $slug) use ($generic_slugs): bool {
        $slug = strtolower(trim($slug));
        $slug = trim($slug, "/");
        return in_array($slug, $generic_slugs, true);
    };

    $is_generic_title = function(string $title) use ($normalize): bool {
        $t = $normalize($title);
        return in_array($t, ['home','contact','contact us','about','about us','products','services','sample page'], true);
    };

    // Detect contact-ish page (light heuristics)
    $looks_like_contact = function(\WP_Post $p) use ($normalize): bool {
        $slug = strtolower(trim((string)($p->post_name ?? '')));
        if ($slug !== '' && strpos($slug, 'contact') !== false) return true;

        $title = $normalize(get_the_title($p));
        if ($title === 'contact' || $title === 'contact us') return true;

        $content = strtolower(wp_strip_all_tags((string)$p->post_content));
        if (strpos($content, 'contact') !== false && (strpos($content, 'email') !== false || strpos($content, 'phone') !== false)) {
            return true;
        }
        return false;
    };

    // Turn a phrase into meaningful tokens (lowercased, punctuation stripped, stopwords removed)
    $keyword_tokens = function(string $phrase) use ($stopwords): array {
        $phrase = html_entity_decode($phrase, ENT_QUOTES | ENT_HTML5, 'UTF-8');
        $phrase = mb_strtolower($phrase);

        // Replace non-letters/numbers with spaces (hyphens -> spaces)
        $phrase = preg_replace('/[^\p{L}\p{N}]+/u', ' ', $phrase);
        $parts  = preg_split('/\s+/u', trim($phrase));

        $tokens = [];
        foreach ($parts as $w) {
            if ($w === '') continue;
            if (mb_strlen($w) < 3) continue;
            if (in_array($w, $stopwords, true)) continue;

            // light plural normalisation: chickens -> chicken
            if (mb_strlen($w) > 3 && mb_substr($w, -1) === 's') {
                $w = mb_substr($w, 0, -1);
            }

            $tokens[] = $w;
        }

        $tokens = array_values(array_unique($tokens));

        // Cap to first 4 tokens so titles don't explode matching
        return array_slice($tokens, 0, 4);
    };

    // Count occurrences of fuzzy match in body-ish chunks (case-insensitive, punctuation tolerant, plural tolerant)
    $fuzzy_count = function(string $text, array $tokens): int {
        if (empty($tokens)) return 0;

        $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');

        // If only one token, count word matches with optional plural s
        if (count($tokens) === 1) {
            $norm = mb_strtolower($text);
            $norm = preg_replace('/[^\p{L}\p{N}]+/u', ' ', $norm);
            $t = preg_quote($tokens[0], '/');
            preg_match_all('/\b' . $t . 's?\b/u', $norm, $m);
            return count($m[0]);
        }

        // For 2+ tokens: count per sentence-ish chunk if ALL tokens appear (order doesn't matter)
        $chunks = preg_split('/[.!?]+/u', $text);
        $count = 0;

        foreach ($chunks as $chunk) {
            $c = mb_strtolower($chunk);
            $c = preg_replace('/[^\p{L}\p{N}]+/u', ' ', $c);

            $ok = true;
            foreach ($tokens as $tok) {
                $t = preg_quote($tok, '/');
                if (!preg_match('/\b' . $t . 's?\b/u', $c)) {
                    $ok = false;
                    break;
                }
            }
            if ($ok) $count++;
        }

        return $count;
    };

    $fuzzy_has = function(string $text, array $tokens) use ($fuzzy_count): bool {
        return $fuzzy_count($text, $tokens) > 0;
    };

    $stars_for = function(int $score, int $max = 5): string {
        $score = max(0, min($max, $score));
        return str_repeat('★', $score) . str_repeat('☆', $max - $score);
    };

    // Summary list (phrase => best score/max)
    $summary = [];

    ob_start();
    ?>
    <div class="wrap">
        <h1>Firefly SEO report</h1>
        <p class="sub">Score out of 5 (Title, URL, H1, Body text, Image ALT). Generic pages (Home/Contact/About/etc) are excluded from optimisation scoring.</p>

        <table>
            <thead>
                <tr>
                    <th style="width:22%;">URL</th>
                    <th style="width:16%;">Page title</th>
                    <th style="width:14%;">H1 content</th>
                    <th style="width:12%;">Keyword in body</th>
                    <th style="width:12%;">Keyword in image ALT</th>
                    <th style="width:12%;">Score</th>
                    <th style="width:12%;">Alerts</th>
                </tr>
            </thead>
            <tbody>
            <?php
            if (empty($pages)) {
                echo '<tr><td colspan="7" class="muted">No published pages found.</td></tr>';
            } else {

                foreach ($pages as $p) {
                    $pid   = (int)$p->ID;
                    $title = get_the_title($p);
                    $url   = get_permalink($p);
                    $slug  = (string)($p->post_name ?? '');

                    // Render blocks/shortcodes to HTML
                    $rendered = apply_filters('the_content', $p->post_content);

                    // Extract first H1 from rendered HTML
                    $h1 = '';
                    $has_h1 = false;
                    if (preg_match('/<h1\b[^>]*>(.*?)<\/h1>/is', (string)$rendered, $m)) {
                        $h1 = trim(html_entity_decode(wp_strip_all_tags($m[1]), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
                        if ($h1 !== '') $has_h1 = true;
                    }

                    // ---- keyword selection:
                    // prefer page title unless it's generic; if generic, use H1 if non-generic; else excluded
                    $keyword = '';
                    if (!$is_generic_title($title)) {
                        $keyword = $title;
                    } elseif ($has_h1 && !$is_generic_title($h1)) {
                        $keyword = $h1;
                    } else {
                        $keyword = ''; // excluded
                    }

                    // ---- scoring flags (out of 5)
                    $slug_generic  = $is_generic_slug($slug);
                    $title_generic = $is_generic_title($title);
                    $h1_generic    = ($has_h1 ? $is_generic_title($h1) : true);

                    $score_title = (!$title_generic ? 1 : 0);
                    $score_url   = (!$slug_generic ? 1 : 0);
                    $score_h1    = ($has_h1 && !$h1_generic ? 1 : 0);

                    // Fuzzy keyword tokens
                    $tokens = ($keyword !== '') ? $keyword_tokens($keyword) : [];

                    // Body keyword count excluding H1
                    $body_count = 0;
                    $body_score = 0;
                    if ($keyword !== '') {
                        $html_wo_h1 = preg_replace('/<h1\b[^>]*>.*?<\/h1>/is', ' ', (string)$rendered, 1);
                        $body_text  = html_entity_decode(wp_strip_all_tags((string)$html_wo_h1), ENT_QUOTES | ENT_HTML5, 'UTF-8');
                        $body_count = $fuzzy_count($body_text, $tokens);
                        $body_score = ($body_count > 0 ? 1 : 0);
                    }

                    // ALT keyword match count (counts images whose alt contains the keyword fuzzily)
                    $alt_match_count = 0;
                    $alt_score = 0;
                    if ($keyword !== '') {
                        if (preg_match_all('/<img\b[^>]*\balt\s*=\s*([\'"])(.*?)\1[^>]*>/is', (string)$rendered, $mm)) {
                            foreach ($mm[2] as $alt) {
                                $alt_text = html_entity_decode(wp_strip_all_tags((string)$alt), ENT_QUOTES | ENT_HTML5, 'UTF-8');
                                if ($alt_text !== '' && $fuzzy_has($alt_text, $tokens)) {
                                    $alt_match_count++;
                                }
                            }
                        }
                        $alt_score = ($alt_match_count > 0 ? 1 : 0);
                    }

                    // If keyword excluded (generic page), score must be 0/5 (your requirement)
                    if ($keyword === '') {
                        $score_title = 0;
                        $score_url   = 0;
                        $score_h1    = 0;
                        $body_score  = 0;
                        $alt_score   = 0;
                        $body_count  = 0;
                        $alt_match_count = 0;
                    }

                    $score_total = $score_title + $score_url + $score_h1 + $body_score + $alt_score;

                    // Alerts
                    $alerts = [];
                    if (!$has_h1) $alerts[] = 'Missing H1';
                    if ($slug_generic) $alerts[] = 'Generic URL slug';

                    // Rename warnings (shown in title column)
                    $rename_warning = false;

                    // Home page named "Home"
                    if ($pid === $front_id && $normalize($title) === 'home') {
                        $rename_warning = true;
                    }

                    // Contact page called Contact/Contact Us
                    if ($looks_like_contact($p) && in_array($normalize($title), ['contact','contact us'], true)) {
                        $rename_warning = true;
                    }

                    // Add to summary (exclude generic pages)
                    if ($keyword !== '') {
                        $phrase = $keyword;
                        if (!isset($summary[$phrase]) || $score_total > $summary[$phrase]['score']) {
                            $summary[$phrase] = [
                                'score' => $score_total,
                                'max'   => 5,
                                'url'   => $url,
                                'stars' => $stars_for($score_total, 5),
                            ];
                        }
                    }

                    echo '<tr>';

                    // URL column
                    echo '<td>';
                    echo '<a href="' . esc_url($url) . '" target="_blank" rel="noopener noreferrer">' . esc_html($url) . '</a>';
                    if ($slug_generic && $slug !== '') {
                        echo '<div class="ff-warn" style="margin-top:6px;">Generic URL slug: ' . esc_html($slug) . '</div>';
                    }
                    echo '</td>';

                    // Page Title column
                    echo '<td>';
                    echo '<div>' . esc_html($title) . '</div>';
                    if ($rename_warning) {
                        echo '<div class="ff-warn" style="margin-top:6px;">Rename this page meaningfully</div>';
                    }
                    if ($keyword === '') {
                        echo '<div class="muted" style="margin-top:6px;">Excluded (generic page)</div>';
                    }
                    echo '</td>';

                    // H1 column
                    if ($has_h1 && !$h1_generic) {
                        echo '<td>' . esc_html($h1) . '</td>';
                    } else {
                        echo '<td class="ff-bad">No H1</td>';
                    }

                    // Keyword in body column
                    if ($keyword === '') {
                        echo '<td class="muted">—</td>';
                    } else {
                        if ($body_count > 0) {
                            echo '<td><span class="ff-good">Yes</span> <span class="muted">(' . (int)$body_count . ')</span></td>';
                        } else {
                            echo '<td><span class="ff-bad">No</span> <span class="muted">(0)</span></td>';
                        }
                    }

                    // Keyword in ALT column
                    if ($keyword === '') {
                        echo '<td class="muted">—</td>';
                    } else {
                        if ($alt_match_count > 0) {
                            echo '<td><span class="ff-good">Yes</span> <span class="muted">(' . (int)$alt_match_count . ')</span></td>';
                        } else {
                            echo '<td><span class="ff-bad">No</span> <span class="muted">(0)</span></td>';
                        }
                    }

                    // Score column (stars + numeric)
                    $stars = $stars_for((int)$score_total, 5);
                    echo '<td>';
                    echo '<span class="ff-score"><span class="ff-stars" aria-label="Score stars">' . esc_html($stars) . '</span><span>' . esc_html((string)$score_total) . '/5</span></span>';
                    echo '</td>';

                    // Alerts column
                    echo '<td>';
                    if (!empty($alerts)) {
                        foreach ($alerts as $a) {
                            echo '<span class="ff-warn">' . esc_html($a) . '</span>';
                        }
                    } else {
                        echo '<span class="muted">—</span>';
                    }
                    echo '</td>';

                    echo '</tr>';
                }
            }
            ?>
            </tbody>
        </table>

        <?php
        // ---- Summary report (sorted highest score first)
        if (!empty($summary)) {
            uasort($summary, function($a, $b){
                if ($a['score'] === $b['score']) return 0;
                return ($a['score'] > $b['score']) ? -1 : 1;
            });

            echo '<div class="ff-summary">';
            echo '<h2>This site is optimised for the following words and phrases:</h2>';

            foreach ($summary as $phrase => $info) {
                echo '<div class="line">';
                echo '<div class="phrase">' . esc_html('"' . $phrase . '"') . '</div>';
                echo '<div class="ff-stars" aria-label="Summary stars">' . esc_html($info['stars']) . '</div>';
                echo '<div class="score">' . esc_html($info['score'] . '/' . $info['max']) . '</div>';
                echo '</div>';
            }

            echo '</div>';
        }
        ?>

    </div>
    <?php

    echo ob_get_clean();
    wp_die();
});
