<?php

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

class AIEO_DMM_Ratings extends AIEO_DMM_Module_Base {

    public function get_id()       { return 'ratings'; }
    public function get_label()    { return __('Star Ratings Analytics', 'ai-eshop-optimizer'); }
    public function get_priority() { return 69; } 
    public function get_group()    { return 'customer_profiling'; }

    public function register_hooks() {
        add_action('wp_ajax_aieo_dmm_ratings_save_settings',   array($this, 'ajax_save_settings'));
        add_action('wp_ajax_aieo_dmm_ratings_save_appearance', array($this, 'ajax_save_appearance'));
    }

    public function enqueue_admin_assets() {
        wp_enqueue_style('wp-color-picker');
        wp_enqueue_script('wp-color-picker');
        wp_add_inline_script('wp-color-picker',
            'jQuery(function($){$(".aieo-dmm-ratings-color").wpColorPicker();});'
        );
    }

    
    public function ajax_save_settings() {
        AIEO_DMM::verify_ajax_request();

        $cur = AIEO_Ratings::get_settings();
        $bool_keys = array('enabled', 'require_login', 'display_archive', 'display_single', 'aggregate_only_archive', 'allow_clear', 'display_full_until_rated', 'seo_schema_enabled');
        foreach ($bool_keys as $k) {
            $cur[$k] = !empty($_POST[$k]) ? 1 : 0;
        }
        if (isset($_POST['login_redirect_mode'])) {
            $v = sanitize_key(wp_unslash((string) $_POST['login_redirect_mode']));
            $cur['login_redirect_mode'] = in_array($v, array('redirect', 'event'), true) ? $v : 'redirect';
        }
        if (isset($_POST['caption_format'])) {
            $cur['caption_format'] = sanitize_text_field(wp_unslash((string) $_POST['caption_format']));
        }
        if (isset($_POST['caption_before_rated'])) {
            $cur['caption_before_rated'] = sanitize_text_field(wp_unslash((string) $_POST['caption_before_rated']));
        }
        if (isset($_POST['min_votes_for_display'])) {
            $cur['min_votes_for_display'] = max(0, (int) wp_unslash($_POST['min_votes_for_display']));
        }
        if (isset($_POST['size'])) {
            $cur['size'] = max(8, min(96, (int) wp_unslash($_POST['size'])));
        }
        
        foreach (array('size_mobile', 'size_single') as $k) {
            if (isset($_POST[$k])) {
                $v = (int) wp_unslash($_POST[$k]);
                $cur[$k] = $v <= 0 ? 0 : max(8, min(96, $v));
            }
        }
        
        if (isset($_POST['gap'])) {
            $cur['gap'] = max(0, min(20, (int) wp_unslash($_POST['gap'])));
        }
        if (isset($_POST['gap_mobile'])) {
            $v = (int) wp_unslash($_POST['gap_mobile']);
            $cur['gap_mobile'] = $v <= 0 ? 0 : max(0, min(20, $v));
        }
        
        foreach (array('caption_size', 'caption_size_mobile', 'caption_size_archive', 'caption_size_archive_mobile') as $k) {
            if (isset($_POST[$k])) {
                $cur[$k] = max(8, min(48, (int) wp_unslash($_POST[$k])));
            }
        }
        foreach (array('color_empty', 'color_filled', 'color_hover', 'color_pre_rated') as $k) {
            if (isset($_POST[$k])) {
                $v = sanitize_hex_color(wp_unslash((string) $_POST[$k]));
                if ($v !== null && $v !== '') { $cur[$k] = $v; }
            }
        }

        update_option(AIEO_Ratings::SETTINGS_OPTION, $cur, false);
        wp_send_json_success(array('message' => __('Star Ratings settings saved.', 'ai-eshop-optimizer')));
    }

    
    public function ajax_save_appearance() {
        AIEO_DMM::verify_ajax_request();

        $cur = AIEO_Ratings::get_settings();

        
        foreach (array('color_empty', 'color_filled', 'color_hover', 'color_pre_rated') as $k) {
            if (isset($_POST[$k])) {
                $v = sanitize_hex_color(wp_unslash((string) $_POST[$k]));
                if ($v !== null && $v !== '') { $cur[$k] = $v; }
            }
        }
        
        if (isset($_POST['size'])) {
            $cur['size'] = max(8, min(96, (int) wp_unslash($_POST['size'])));
        }
        foreach (array('size_mobile', 'size_single') as $k) {
            if (isset($_POST[$k])) {
                $v = (int) wp_unslash($_POST[$k]);
                if ($v <= 0) { $cur[$k] = 0; }
                else         { $cur[$k] = max(8, min(96, $v)); }
            }
        }
        
        if (isset($_POST['gap'])) {
            $cur['gap'] = max(0, min(20, (int) wp_unslash($_POST['gap'])));
        }
        if (isset($_POST['gap_mobile'])) {
            $v = (int) wp_unslash($_POST['gap_mobile']);
            $cur['gap_mobile'] = $v <= 0 ? 0 : max(0, min(20, $v));
        }
        
        foreach (array('caption_size', 'caption_size_mobile', 'caption_size_archive', 'caption_size_archive_mobile') as $k) {
            if (isset($_POST[$k])) {
                $cur[$k] = max(8, min(48, (int) wp_unslash($_POST[$k])));
            }
        }

        update_option(AIEO_Ratings::SETTINGS_OPTION, $cur, false);
        wp_send_json_success(array('message' => __('Star Ratings appearance saved.', 'ai-eshop-optimizer')));
    }

    public function render_subtab() {
        global $wpdb;
        $events = $wpdb->prefix . 'aieo_ratings';
        $stats  = $wpdb->prefix . 'aieo_rating_stats';

        $events_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $events)) === $events;
        $stats_exists  = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $stats))  === $stats;

        
        
        
        echo '<div class="aieo-dmm-section"><p class="description" style="font-size:12px;">';
        echo wp_kses_post(sprintf(
            
            __('Looking for the Star Ratings display settings (behavior, captions, colors, sizes)? They now live under %1$sVisual Display → Star Ratings Display%2$s.', 'ai-eshop-optimizer'),
            '<a href="' . esc_url(add_query_arg(array('page' => AIEO_DMM::MENU_SLUG, 'dmm_tab' => 'ratings_display'), admin_url('admin.php'))) . '">',
            '</a>'
        ));
        echo '</p></div>';

        if (!$events_exists || !$stats_exists) {
            echo '<div class="aieo-dmm-section">';
            echo '<h2>' . esc_html__('Star Ratings analytics', 'ai-eshop-optimizer') . '</h2>';
            echo '<div class="aieo-dmm-card"><p>'
                . esc_html__('No rating tables yet — they install lazily on the next frontend hit. Visit any frontend page once and the analytics will appear here.', 'ai-eshop-optimizer')
                . '</p></div>';
            echo '</div>';
            return;
        }

        $total_events    = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$events}");
        $unique_voters_u = (int) $wpdb->get_var("SELECT COUNT(DISTINCT user_id) FROM {$events} WHERE user_id > 0");
        $unique_voters_s = (int) $wpdb->get_var("SELECT COUNT(DISTINCT session_token) FROM {$events} WHERE user_id = 0 AND session_token <> ''");
        $rated_products  = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$stats} WHERE count_total > 0");
        $row_global      = $wpdb->get_row("SELECT SUM(sum_total) AS s, SUM(count_total) AS c FROM {$stats}", ARRAY_A);
        $global_avg      = ($row_global && (int) $row_global['c'] > 0) ? round((float) $row_global['s'] / (int) $row_global['c'], 2) : 0;

        $top      = $wpdb->get_results("SELECT product_id, count_total, sum_total FROM {$stats} WHERE count_total >= 3 ORDER BY (sum_total / count_total) DESC, count_total DESC LIMIT 20");
        $bottom   = $wpdb->get_results("SELECT product_id, count_total, sum_total FROM {$stats} WHERE count_total >= 3 ORDER BY (sum_total / count_total) ASC,  count_total DESC LIMIT 20");
        $most     = $wpdb->get_results("SELECT product_id, count_total, sum_total FROM {$stats} ORDER BY count_total DESC LIMIT 20");
        $by_source = $wpdb->get_results("SELECT source, COUNT(*) AS c FROM {$events} WHERE source <> '' GROUP BY source ORDER BY c DESC LIMIT 10");
        $row_dist  = $wpdb->get_row("SELECT SUM(n1) AS n1, SUM(n2) AS n2, SUM(n3) AS n3, SUM(n4) AS n4, SUM(n5) AS n5 FROM {$stats}", ARRAY_A);

        echo '<div class="aieo-dmm-section">';
        echo '<h2>' . esc_html__('Star Ratings analytics', 'ai-eshop-optimizer') . '</h2>';
        echo '<p class="description">'
            . esc_html__('How many shoppers rate, what they rate, and which products they like best.', 'ai-eshop-optimizer') . '</p>';

        
        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('Overview', 'ai-eshop-optimizer') . '</h3>';
        echo '<div class="aieo-attr-tiles">';
        $this->tile(__('Total rating events', 'ai-eshop-optimizer'),     number_format_i18n($total_events));
        $this->tile(__('Rated products',        'ai-eshop-optimizer'),   number_format_i18n($rated_products));
        $this->tile(__('Voters — logged in',     'ai-eshop-optimizer'),  number_format_i18n($unique_voters_u));
        $this->tile(__('Voters — anonymous',     'ai-eshop-optimizer'),  number_format_i18n($unique_voters_s));
        $this->tile(__('Site-wide average',     'ai-eshop-optimizer'),   $global_avg > 0 ? number_format_i18n($global_avg, 2) . ' / 5' : '—');
        $total_votes_now = (int) $wpdb->get_var("SELECT SUM(count_total) FROM {$stats}");
        $this->tile(__('Active votes',          'ai-eshop-optimizer'),   number_format_i18n((int) $total_votes_now));
        echo '</div></div>';

        $this->render_distribution_card($row_dist);
        $this->render_source_card($by_source, $total_events);
        $this->render_top_card(__('Top rated', 'ai-eshop-optimizer'), $top, true);
        $this->render_top_card(__('Lowest rated', 'ai-eshop-optimizer'), $bottom, true);
        $this->render_top_card(__('Most votes', 'ai-eshop-optimizer'), $most, false);

        echo '</div>';
    }

    
    public function render_settings_card() {
        $s = AIEO_Ratings::get_settings();

        echo '<form id="aieo-dmm-ratings-form" class="aieo-dmm-form">';

        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('Behavior', 'ai-eshop-optimizer') . '</h3>';
        echo '<table class="form-table">';
        echo '<tr><th>' . esc_html__('Enable Star Ratings', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="enabled" value="1" ' . checked(!empty($s['enabled']), true, false) . '> '
            . esc_html__('Master switch for the module.', 'ai-eshop-optimizer') . '</label></td></tr>';
        echo '<tr><th>' . esc_html__('Require login to vote', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="require_login" value="1" ' . checked(!empty($s['require_login']), true, false) . '> '
            . esc_html__('Anonymous shoppers see the widget but clicks are gated.', 'ai-eshop-optimizer') . '</label></td></tr>';
        echo '<tr><th>' . esc_html__('Login gate behavior', 'ai-eshop-optimizer') . '</th>'
            . '<td><select name="login_redirect_mode">'
            .   '<option value="redirect" ' . selected((string) $s['login_redirect_mode'], 'redirect', false) . '>' . esc_html__('Redirect to login page', 'ai-eshop-optimizer') . '</option>'
            .   '<option value="event" '    . selected((string) $s['login_redirect_mode'], 'event',    false) . '>' . esc_html__('Emit aieo:rating:login_required event (theme-handled)', 'ai-eshop-optimizer') . '</option>'
            . '</select></td></tr>';
        echo '<tr><th>' . esc_html__('Allow clear', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="allow_clear" value="1" ' . checked(!empty($s['allow_clear']), true, false) . '> '
            . esc_html__('Re-clicking the active star clears the rating.', 'ai-eshop-optimizer') . '</label></td></tr>';
        echo '</table></div>';

        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('Where it appears', 'ai-eshop-optimizer') . '</h3>';
        echo '<table class="form-table">';
        echo '<tr><th>' . esc_html__('Display on archive cards', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="display_archive" value="1" ' . checked(!empty($s['display_archive']), true, false) . '> '
            . esc_html__('Render on shop / category pages.', 'ai-eshop-optimizer') . '</label></td></tr>';
        echo '<tr><th>' . esc_html__('Display on single product page', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="display_single" value="1" ' . checked(!empty($s['display_single']), true, false) . '> '
            . esc_html__('Render between the title and the price.', 'ai-eshop-optimizer') . '</label></td></tr>';
        echo '<tr><th>' . esc_html__('Aggregate only on archive', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="aggregate_only_archive" value="1" ' . checked(!empty($s['aggregate_only_archive']), true, false) . '> '
            . esc_html__('Archive cards show the read-only aggregate (no interactive widget).', 'ai-eshop-optimizer') . '</label></td></tr>';
        echo '<tr><th>' . esc_html__('Show 5 stars until rated', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="display_full_until_rated" value="1" ' . checked(!empty($s['display_full_until_rated']), true, false) . '> '
            . esc_html__('Display all 5 stars filled (and hide the avg/count caption) until the viewer casts their own rating. After they vote, the widget switches to the true aggregate.', 'ai-eshop-optimizer') . '</label></td></tr>';
        echo '</table></div>';

        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('Caption + thresholds', 'ai-eshop-optimizer') . '</h3>';
        echo '<table class="form-table">';
        echo '<tr><th>' . esc_html__('Prompt before viewer rates', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="text" name="caption_before_rated" value="' . esc_attr((string) $s['caption_before_rated']) . '" class="regular-text">'
            . '<p class="description">' . esc_html__('Shown next to the stars until the viewer casts their own rating. Plain text — no tokens.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Caption after viewer rates', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="text" name="caption_format" value="' . esc_attr((string) $s['caption_format']) . '" class="regular-text">'
            
            . '<p class="description">' . esc_html__('Tokens: %avg, %count, %avg5. Empty = hide caption entirely.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Minimum votes to show aggregate', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="0" name="min_votes_for_display" value="' . (int) $s['min_votes_for_display'] . '" class="small-text">'
            . '<p class="description">' . esc_html__('Hide the aggregate until N votes — avoids "5.0 (1)" being misleading.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '</table></div>';

        
        
        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('Appearance', 'ai-eshop-optimizer') . '</h3>';
        echo '<table class="form-table">';
        echo '<tr><th>' . esc_html__('Empty (outline) color', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="text" name="color_empty" value="' . esc_attr((string) $s['color_empty']) . '" class="aieo-dmm-ratings-color" data-default-color="#d4d4d8"></td></tr>';
        echo '<tr><th>' . esc_html__('Pre-rated color', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="text" name="color_pre_rated" value="' . esc_attr((string) ($s['color_pre_rated'] ?? '#000000')) . '" class="aieo-dmm-ratings-color" data-default-color="#000000">'
            . '<p class="description">' . esc_html__('Color of the 5 placeholder stars before the viewer has rated.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Rated (filled) color', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="text" name="color_filled" value="' . esc_attr((string) $s['color_filled']) . '" class="aieo-dmm-ratings-color" data-default-color="#F46767">'
            . '<p class="description">' . esc_html__('Color of the stars representing the viewer&rsquo;s own rating, after they vote.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Hover color', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="text" name="color_hover" value="' . esc_attr((string) $s['color_hover']) . '" class="aieo-dmm-ratings-color" data-default-color="#F46767"></td></tr>';
        echo '<tr><th>' . esc_html__('Star size — desktop (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="8" max="96" name="size" value="' . (int) $s['size'] . '" class="small-text">'
            . '<p class="description">' . esc_html__('Default size used everywhere. The two overrides below kick in on top of this.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Star size — mobile (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="0" max="96" name="size_mobile" value="' . (int) ($s['size_mobile'] ?? 0) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Applied on viewports ≤ 768px wide. Set 0 to inherit the desktop size.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Star size — single-product page (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="0" max="96" name="size_single" value="' . (int) ($s['size_single'] ?? 0) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Applied only on the single-product page (body.single-product). Set 0 to inherit the desktop size. Note: on mobile single-product pages the mobile size wins.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Star gap — desktop (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="0" max="20" name="gap" value="' . (int) ($s['gap'] ?? 2) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Horizontal distance between adjacent stars in the row. 0 = stars touching · 2 = the dev theme reference · 8 = airy. Range 0–20px.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Star gap — mobile (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="0" max="20" name="gap_mobile" value="' . (int) ($s['gap_mobile'] ?? 0) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Applied on viewports ≤ 768px wide. Set 0 to inherit the desktop gap. Tighter values (1–2px) prevent the row inflating to fill narrow archive cards.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Caption text size — product, desktop (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="8" max="48" name="caption_size" value="' . (int) ($s['caption_size'] ?? 13) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Font size of the rating caption (e.g. “4.6 (128)” / the prompt) on product / single pages.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Caption text size — product, mobile (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="8" max="48" name="caption_size_mobile" value="' . (int) ($s['caption_size_mobile'] ?? 13) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Applied on viewports ≤ 768px wide.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Caption text size — archive, desktop (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="8" max="48" name="caption_size_archive" value="' . (int) ($s['caption_size_archive'] ?? 12) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Font size of the caption on shop / category archive cards.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '<tr><th>' . esc_html__('Caption text size — archive, mobile (px)', 'ai-eshop-optimizer') . '</th>'
            . '<td><input type="number" min="8" max="48" name="caption_size_archive_mobile" value="' . (int) ($s['caption_size_archive_mobile'] ?? 11) . '" class="small-text">'
            . '<p class="description">' . esc_html__('Applied on archive cards on viewports ≤ 768px wide.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '</table></div>';

        
        
        
        
        
        
        
        
        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('SEO / Schema', 'ai-eshop-optimizer') . '</h3>';
        echo '<p class="description" style="margin:0 0 12px;">'
            . esc_html__('Google reads JSON-LD on product pages to render the star rich-snippet under each search result. When enabled, the AIEO rating aggregate (count + average from wp_aieo_rating_stats) is injected into the Product schema emitted by AIOSEO, Yoast SEO, or Rank Math — whichever you have active. Falls back to its own minimal JSON-LD if none is detected.', 'ai-eshop-optimizer')
            . '</p>';
        echo '<table class="form-table">';
        echo '<tr><th>' . esc_html__('Feed schema with AIEO ratings', 'ai-eshop-optimizer') . '</th>'
            . '<td><label><input type="checkbox" name="seo_schema_enabled" value="1" ' . checked(!empty($s['seo_schema_enabled']), true, false) . '> '
            . esc_html__('Inject aggregateRating into Product JSON-LD on single-product pages.', 'ai-eshop-optimizer') . '</label>'
            . '<p class="description">' . esc_html__('Reads from the materialized stats table — no per-vote computation, no comment-system dependency.', 'ai-eshop-optimizer') . '</p></td></tr>';
        echo '</table></div>';

        echo '<p class="submit">';
        echo '<button type="submit" class="button button-primary aieo-dmm-btn-fixed" data-action="aieo_dmm_ratings_save_settings">';
        echo esc_html__('Save settings', 'ai-eshop-optimizer') . '</button></p>';
        echo '</form>';
    }

    private function render_distribution_card($row) {
        $row = is_array($row) ? $row : array();
        $n   = array(
            1 => (int) ($row['n1'] ?? 0),
            2 => (int) ($row['n2'] ?? 0),
            3 => (int) ($row['n3'] ?? 0),
            4 => (int) ($row['n4'] ?? 0),
            5 => (int) ($row['n5'] ?? 0),
        );
        $total = array_sum($n);

        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('Site-wide rating distribution', 'ai-eshop-optimizer') . '</h3>';
        echo '<p class="description" style="margin:0 0 8px;">'
            . esc_html__('How votes break down across the 5 stars. Bigger 4–5 buckets vs 1–2 = healthy product mix.', 'ai-eshop-optimizer') . '</p>';
        echo '<table class="widefat striped">';
        echo '<thead><tr><th style="width:80px;">' . esc_html__('Rating', 'ai-eshop-optimizer') . '</th>';
        echo '<th>' . esc_html__('Distribution', 'ai-eshop-optimizer') . '</th>';
        echo '<th style="width:120px;text-align:right;">' . esc_html__('Votes', 'ai-eshop-optimizer') . '</th></tr></thead><tbody>';
        for ($i = 5; $i >= 1; $i--) {
            $pct = $total > 0 ? round(100 * $n[$i] / $total, 1) : 0;
            echo '<tr>';
            echo '<td><strong>' . str_repeat('★', $i) . '</strong></td>'; 
            echo '<td><div style="background:#f3f4f6;border-radius:4px;overflow:hidden;height:14px;">';
            echo '<div style="height:14px;background:#f5b800;width:' . esc_attr((string) $pct) . '%;"></div>';
            echo '</div><span style="font-size:12px;color:#1f2937;">' . esc_html((string) $pct) . '%</span></td>';
            echo '<td style="text-align:right;">' . esc_html(number_format_i18n($n[$i])) . '</td>';
            echo '</tr>';
        }
        echo '</tbody></table></div>';
    }

    private function render_source_card($rows, $total_events) {
        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html__('Where ratings come from', 'ai-eshop-optimizer') . '</h3>';
        echo '<p class="description" style="margin:0 0 8px;">'
            . esc_html__('Source breakdown: which surface the shopper was on when they rated.', 'ai-eshop-optimizer') . '</p>';
        echo '<table class="widefat striped aieo-attr-sortable-table">';
        echo '<thead><tr>';
        echo '<th data-sort-type="text">' . esc_html__('Source', 'ai-eshop-optimizer') . ' <span class="aieo-attr-dt-sort-ind">⇅</span></th>';
        echo '<th data-sort-type="num">'  . esc_html__('Events', 'ai-eshop-optimizer') . ' <span class="aieo-attr-dt-sort-ind">⇅</span></th>';
        echo '<th data-sort-type="num">'  . esc_html__('Percentage', 'ai-eshop-optimizer') . ' <span class="aieo-attr-dt-sort-ind">⇅</span></th>';
        echo '</tr></thead><tbody>';
        if (empty($rows)) {
            echo '<tr><td colspan="3" style="text-align:center;color:#646970;">'
                . esc_html__('No rating events yet.', 'ai-eshop-optimizer') . '</td></tr>';
        } else {
            foreach ($rows as $r) {
                $pct = $total_events > 0 ? round(100 * ((int) $r->c) / $total_events, 1) : 0;
                echo '<tr>';
                echo '<td data-sort-value="' . esc_attr((string) $r->source) . '"><code>' . esc_html((string) $r->source) . '</code></td>';
                echo '<td data-sort-value="' . (int) $r->c . '">' . (int) $r->c . '</td>';
                echo '<td data-sort-value="' . esc_attr((string) $pct) . '">';
                echo '<div style="display:inline-block;min-width:120px;background:#f3f4f6;border-radius:4px;overflow:hidden;vertical-align:middle;">';
                echo '<div style="height:14px;background:#4f46e5;width:' . esc_attr((string) $pct) . '%;"></div>';
                echo '</div> <span style="color:#1f2937;font-size:12px;">' . esc_html((string) $pct) . '%</span>';
                echo '</td>';
                echo '</tr>';
            }
        }
        echo '</tbody></table></div>';
    }

    
    private function render_top_card($title, $rows, $show_avg) {
        echo '<div class="aieo-dmm-card">';
        echo '<h3>' . esc_html($title) . '</h3>';
        if (empty($rows)) {
            echo '<p style="color:#646970;">' . esc_html__('Not enough rating data yet (each product needs at least 3 votes to appear here).', 'ai-eshop-optimizer') . '</p>';
            echo '</div>';
            return;
        }
        echo '<table class="widefat striped aieo-attr-sortable-table">';
        echo '<thead><tr>';
        echo '<th style="width:50px;">#</th>';
        echo '<th data-sort-type="text">' . esc_html__('Product', 'ai-eshop-optimizer') . ' <span class="aieo-attr-dt-sort-ind">⇅</span></th>';
        echo '<th data-sort-type="num">'  . esc_html__('Avg', 'ai-eshop-optimizer') . ' <span class="aieo-attr-dt-sort-ind">⇅</span></th>';
        echo '<th data-sort-type="num">'  . esc_html__('Votes', 'ai-eshop-optimizer') . ' <span class="aieo-attr-dt-sort-ind">⇅</span></th>';
        echo '<th>' . esc_html__('Actions', 'ai-eshop-optimizer') . '</th>';
        echo '</tr></thead><tbody>';
        foreach ($rows as $i => $r) {
            $pid    = (int) $r->product_id;
            $count  = (int) $r->count_total;
            $sum    = (int) $r->sum_total;
            $avg    = $count > 0 ? round($sum / $count, 2) : 0;
            $title  = $pid > 0 ? get_the_title($pid) : '';
            if ($title === '' || $title === null) { $title = '#' . $pid . ' ' . __('(deleted)', 'ai-eshop-optimizer'); }
            $permalink = $pid > 0 ? get_permalink($pid) : '';
            $edit_url  = $pid > 0 ? admin_url('post.php?post=' . $pid . '&action=edit') : '';
            echo '<tr>';
            echo '<td>' . (int) ($i + 1) . '</td>';
            echo '<td data-sort-value="' . esc_attr($title) . '">';
            if ($edit_url) {
                echo '<strong><a href="' . esc_url($edit_url) . '">' . esc_html($title) . '</a></strong>';
            } else {
                echo '<strong>' . esc_html($title) . '</strong>';
            }
            echo '<br><small style="color:#646970;">ID: ' . (int) $pid . '</small>';
            echo '</td>';
            echo '<td data-sort-value="' . esc_attr((string) $avg) . '">' . esc_html(number_format_i18n($avg, 2)) . '</td>';
            echo '<td data-sort-value="' . (int) $count . '">' . esc_html(number_format_i18n($count)) . '</td>';
            echo '<td>';
            if ($permalink) {
                echo '<a href="' . esc_url($permalink) . '" target="_blank" class="button button-small">' . esc_html__('View', 'ai-eshop-optimizer') . '</a>';
            } else {
                echo '—';
            }
            echo '</td>';
            echo '</tr>';
        }
        echo '</tbody></table></div>';
        
        unset($show_avg);
    }

    private function tile($label, $value) {
        echo '<div class="aieo-attr-tile">';
        echo '<div class="aieo-attr-tile-label">' . esc_html($label) . '</div>';
        echo '<div class="aieo-attr-tile-value">' . esc_html((string) $value) . '</div>';
        echo '</div>';
    }
}
