<?php

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

class AIEO_DMM_Price_History extends AIEO_DMM_Module_Base {

    const OPTION_KEY      = 'aieo_price_history_settings';
    const BACKFILL_FLAG   = 'aieo_price_history_backfilled';
    const CRON_HOOK       = 'aieo_price_history_daily';

    public function get_id()       { return 'price_history'; }
    public function get_label()    { return __('Price History (Omnibus)', 'ai-eshop-optimizer'); }
    public function get_priority() { return 10; } 
    public function get_group()    { return 'special_pricing_offers'; }

    public function register_hooks() {
        
        $schema = AIEO_DIR . 'includes/dmm/sql/price-history-schema.php';
        if (file_exists($schema)) {
            require_once $schema;
            if (function_exists('aieo_install_price_history_schema')) { aieo_install_price_history_schema(); }
        }
        if (!class_exists('AIEO_Price_History')) {
            $resolver = AIEO_DIR . 'includes/class-aieo-price-history.php';
            if (file_exists($resolver)) { require_once $resolver; }
        }

        if (!$this->is_enabled()) { return; }

        
        add_action('woocommerce_update_product',           array($this, 'on_product_save'), 20, 1);
        add_action('woocommerce_update_product_variation', array($this, 'on_product_save'), 20, 1);
        add_action('woocommerce_new_product',              array($this, 'on_product_save'), 20, 1);

        
        
        add_action('plugins_loaded', array($this, 'maybe_schedule'), 27);
        add_action(self::CRON_HOOK, array($this, 'cron_sweep'));

        
        add_action('admin_init', array($this, 'maybe_backfill'));

        
        add_action('wp_ajax_aieo_price_history_save',      array($this, 'ajax_save'));
        add_action('wp_ajax_aieo_price_history_backfill',  array($this, 'ajax_backfill'));
        add_action('wp_ajax_aieo_price_history_orderscan', array($this, 'ajax_order_scan'));
        add_action('wp_ajax_aieo_price_history_ordersave', array($this, 'ajax_order_save'));
        add_action('admin_post_aieo_ph_export',            array($this, 'handle_export'));
    }

    
    public function enqueue_admin_assets() {
        if (class_exists('AIEO_DMM_Product_Picker')) { AIEO_DMM_Product_Picker::enqueue_assets(); }
    }

    
    
    

    public function settings() {
        $s = get_option(self::OPTION_KEY, array());
        return array_merge(array('enabled' => true, 'frequency' => 'daily', 'time' => '03:30', 'backfill_since' => '2022-01-01'), is_array($s) ? $s : array());
    }
    public function is_enabled() {
        $s = $this->settings();
        return !empty($s['enabled']);
    }

    
    private function backfill_since_setting() {
        $d = $this->settings();
        $v = isset($d['backfill_since']) ? (string) $d['backfill_since'] : '';
        return preg_match('/^\d{4}-\d{2}-\d{2}$/', $v) ? $v : '2022-01-01';
    }
    
    private function resolve_backfill_since() {
        $v = isset($_POST['since']) ? sanitize_text_field(wp_unslash($_POST['since'])) : '';
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $v)) { return $this->backfill_since_setting(); }
        $d = $this->settings();
        if ((isset($d['backfill_since']) ? (string) $d['backfill_since'] : '') !== $v) {
            $d['backfill_since'] = $v;
            update_option(self::OPTION_KEY, $d, false);
        }
        return $v;
    }

    
    
    

    
    public function on_product_save($product_id) {
        if (!class_exists('AIEO_Price_History') || !function_exists('wc_get_product')) { return; }
        $product = wc_get_product((int) $product_id);
        if ($product) { AIEO_Price_History::record_product($product, 'price_change_hook'); }
    }

    
    
    

    public function maybe_schedule() { $this->reschedule(false); }

    
    private function reschedule($force = false) {
        $cfg  = $this->settings();
        $freq = isset($cfg['frequency']) ? $cfg['frequency'] : 'daily';
        $next = (int) wp_next_scheduled(self::CRON_HOOK);

        if (!$this->is_enabled() || $freq === 'off') {
            if ($next > 0) { wp_clear_scheduled_hook(self::CRON_HOOK); }
            return;
        }
        $desired = ($freq === 'hourly') ? 'hourly' : 'daily';
        if (!$force && wp_get_schedule(self::CRON_HOOK) === $desired && $next > 0) { return; }

        wp_clear_scheduled_hook(self::CRON_HOOK);
        $first = ($freq === 'hourly')
            ? (time() + MINUTE_IN_SECONDS)
            : $this->next_athens_at(isset($cfg['time']) ? $cfg['time'] : '03:30');
        wp_schedule_event($first, $desired, self::CRON_HOOK);
    }

    private function next_athens_at($hhmm) {
        try {
            $tz   = new \DateTimeZone('Europe/Athens');
            $next = new \DateTime('today ' . $hhmm . ':00', $tz);
            if ($next->getTimestamp() <= time()) { $next->modify('+1 day'); }
            return (int) $next->getTimestamp();
        } catch (\Throwable $e) {
            return time() + DAY_IN_SECONDS;
        }
    }

    
    public function cron_sweep() {
        if (!$this->is_enabled()) { return; }
        global $wpdb;
        $ph    = $wpdb->prefix . 'aieo_price_history';
        $posts = $wpdb->posts;
        $pm    = $wpdb->postmeta;
        $cur   = function_exists('get_woocommerce_currency') ? (string) get_woocommerce_currency() : 'EUR';
        $now   = current_time('mysql', true);

        
        
        
        
        
        
        $wpdb->query($wpdb->prepare(
            "INSERT INTO {$ph} (product_id, parent_id, price, regular_price, on_sale, currency, observed_at, source)
             SELECT p.ID, NULLIF(p.post_parent, 0), pmp.pval, pmr.rval,
                    CASE WHEN pmr.rval IS NOT NULL AND pmp.pval < pmr.rval THEN 1 ELSE 0 END,
                    %s, %s, 'cron_snapshot'
             FROM {$posts} p
             JOIN (SELECT post_id, MIN(CAST(meta_value AS DECIMAL(12,4))) AS pval FROM {$pm} WHERE meta_key = '_price' AND meta_value <> '' AND CAST(meta_value AS DECIMAL(12,4)) > 0 GROUP BY post_id) pmp ON pmp.post_id = p.ID
             LEFT JOIN (SELECT post_id, MIN(CAST(meta_value AS DECIMAL(12,4))) AS rval FROM {$pm} WHERE meta_key = '_regular_price' AND meta_value <> '' AND CAST(meta_value AS DECIMAL(12,4)) > 0 GROUP BY post_id) pmr ON pmr.post_id = p.ID
             WHERE p.post_type IN ('product','product_variation')
               AND p.post_status IN ('publish','private')
               AND NOT EXISTS (SELECT 1 FROM {$ph} e WHERE e.product_id = p.ID AND e.currency = %s AND e.price = pmp.pval)",
            $cur, $now, $cur
        ));
        
        
        
        if (function_exists('wp_cache_flush_group')) {
            wp_cache_flush_group(AIEO_Price_History::CACHE_GROUP);
        }
    }

    
    
    

    public function maybe_backfill() {
        if (!$this->is_enabled()) { return; }
        if (get_option(self::BACKFILL_FLAG)) { return; }
        $this->backfill();
        update_option(self::BACKFILL_FLAG, time(), false);
    }

    public function backfill() {
        global $wpdb;
        $ph    = $wpdb->prefix . 'aieo_price_history';
        $posts = $wpdb->posts;
        $pm    = $wpdb->postmeta;
        $cur   = function_exists('get_woocommerce_currency') ? (string) get_woocommerce_currency() : 'EUR';
        $now   = current_time('mysql', true);

        
        
        
        
        return (int) $wpdb->query($wpdb->prepare(
            "INSERT INTO {$ph} (product_id, parent_id, price, regular_price, on_sale, currency, observed_at, source)
             SELECT p.ID, NULLIF(p.post_parent, 0), pmp.pval, pmr.rval,
                    CASE WHEN pmr.rval IS NOT NULL AND pmp.pval < pmr.rval THEN 1 ELSE 0 END,
                    %s, %s, 'backfill'
             FROM {$posts} p
             JOIN (SELECT post_id, MIN(CAST(meta_value AS DECIMAL(12,4))) AS pval FROM {$pm} WHERE meta_key = '_price' AND meta_value <> '' AND CAST(meta_value AS DECIMAL(12,4)) > 0 GROUP BY post_id) pmp ON pmp.post_id = p.ID
             LEFT JOIN (SELECT post_id, MIN(CAST(meta_value AS DECIMAL(12,4))) AS rval FROM {$pm} WHERE meta_key = '_regular_price' AND meta_value <> '' AND CAST(meta_value AS DECIMAL(12,4)) > 0 GROUP BY post_id) pmr ON pmr.post_id = p.ID
             WHERE p.post_type IN ('product','product_variation')
               AND p.post_status IN ('publish','private')
               AND NOT EXISTS (SELECT 1 FROM {$ph} e WHERE e.product_id = p.ID AND e.currency = %s AND e.price = pmp.pval)",
            $cur, $now, $cur
        ));
    }

    
    
    

    public function ajax_save() {
        AIEO_DMM::verify_ajax_request();
        $d = $this->settings();
        
        
        if (isset($_POST['enabled']))   { $d['enabled'] = !empty($_POST['enabled']); }
        if (isset($_POST['frequency'])) {
            $f = sanitize_key((string) wp_unslash($_POST['frequency']));
            $d['frequency'] = in_array($f, array('off', 'hourly', 'daily'), true) ? $f : 'daily';
        }
        if (isset($_POST['time'])) {
            $t = sanitize_text_field((string) wp_unslash($_POST['time']));
            $d['time'] = preg_match('/^\d{2}:\d{2}$/', $t) ? $t : '03:30';
        }
        update_option(self::OPTION_KEY, $d, false);
        $this->reschedule(true);

        $next_at    = (int) wp_next_scheduled(self::CRON_HOOK);
        $next_human = $next_at > 0
            ? human_time_diff($next_at) . ' (' . wp_date('Y-m-d H:i', $next_at) . ')'
            : __('not scheduled', 'ai-eshop-optimizer');
        wp_send_json_success(array('message' => __('Saved.', 'ai-eshop-optimizer'), 'next_at' => $next_at, 'next_human' => $next_human));
    }

    public function ajax_backfill() {
        AIEO_DMM::verify_ajax_request();
        
        
        $rows = $this->backfill();
        $this->cron_sweep();
        update_option(self::BACKFILL_FLAG, time(), false);
        wp_send_json_success(array(
            'message' => sprintf(
                
                __('Snapshot complete — %d new baseline rows written.', 'ai-eshop-optimizer'),
                (int) $rows
            ),
        ));
    }

    
    public function ajax_order_scan() {
        AIEO_DMM::verify_ajax_request();
        global $wpdb;
        $P       = $wpdb->prefix;
        $T       = $P . 'aieo_order_products_analytics';
        $mode    = isset($_POST['mode']) ? sanitize_key((string) wp_unslash($_POST['mode'])) : 'batch';
        $TR_PIDS = 'aieo_ph_scan_pids';
        $since   = $this->resolve_backfill_since() . ' 00:00:00';
        
        
        $pid_expr = "COALESCE(NULLIF(variation_id, 0), product_id)";
        $keep     = "date_created_gmt >= '{$since}' AND unit_price > 0 AND COALESCE(prof_discount, '') <> 'NAI'";

        if (!$wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $T))) {
            wp_send_json_error(array('message' => __('AIEO order-products table not found — run the order stats first.', 'ai-eshop-optimizer')));
        }

        if ($mode === 'init') {
            $pids = $wpdb->get_col("SELECT DISTINCT {$pid_expr} AS pid FROM {$T} WHERE {$keep} AND {$pid_expr} > 0 ORDER BY pid");
            $pids = array_values(array_filter(array_map('intval', (array) $pids)));
            set_transient($TR_PIDS, $pids, 2 * HOUR_IN_SECONDS);
            wp_send_json_success(array('total' => count($pids)));
        }

        $offset = isset($_POST['offset']) ? max(0, (int) $_POST['offset']) : 0;
        $size   = 500;
        $pids   = get_transient($TR_PIDS);
        if (!is_array($pids)) {
            wp_send_json_error(array('message' => __('Scan session expired — click Scan again.', 'ai-eshop-optimizer')));
        }
        $slice = array_slice($pids, $offset, $size);
        if (empty($slice)) {
            wp_send_json_success(array('done' => true, 'processed' => count($pids), 'total' => count($pids), 'batch_prices' => 0));
        }
        $in_pids = implode(',', array_map('intval', $slice));

        $batch_prices = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM (
                SELECT {$pid_expr} AS pid, ROUND(unit_price, 2) AS up
                FROM {$T}
                WHERE {$keep} AND {$pid_expr} IN ({$in_pids})
                GROUP BY pid, up
            ) t"
        );
        $processed = $offset + count($slice);
        wp_send_json_success(array(
            'done'         => ($processed >= count($pids)),
            'processed'    => $processed,
            'total'        => count($pids),
            'batch_prices' => $batch_prices,
        ));
    }

    
    public function ajax_order_save() {
        AIEO_DMM::verify_ajax_request();
        global $wpdb;
        $P  = $wpdb->prefix;
        $T  = $P . 'aieo_order_products_analytics';
        $PH = $P . 'aieo_price_history';
        if (!$wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $T))) {
            wp_send_json_error(array('message' => __('AIEO order-products table not found.', 'ai-eshop-optimizer')));
        }
        if (function_exists('aieo_install_price_history_schema')) { aieo_install_price_history_schema(); }

        $since    = $this->resolve_backfill_since() . ' 00:00:00';
        $currency = class_exists('AIEO_Price_History') ? AIEO_Price_History::default_currency() : (function_exists('get_woocommerce_currency') ? get_woocommerce_currency() : 'EUR');
        $currency = preg_replace('/[^A-Z]/', '', strtoupper((string) $currency));
        if ($currency === '') { $currency = 'EUR'; }

        
        $wpdb->query("DELETE FROM {$PH} WHERE source = 'order_backfill'");
        $inserted = $wpdb->query(
            "INSERT INTO {$PH} (product_id, parent_id, price, regular_price, on_sale, currency, observed_at, source)
             SELECT pid, parent_id, up, reg, onsale, '{$currency}', earliest, 'order_backfill'
             FROM (
                SELECT COALESCE(NULLIF(variation_id, 0), product_id) AS pid,
                       MAX(CASE WHEN variation_id > 0 THEN parent_product_id ELSE 0 END) AS parent_id,
                       ROUND(unit_price, 2) AS up,
                       NULLIF(MAX(ROUND(list_price, 2)), 0) AS reg,
                       MAX(CASE WHEN list_price > unit_price THEN 1 ELSE 0 END) AS onsale,
                       MIN(date_created_gmt) AS earliest
                FROM {$T}
                WHERE date_created_gmt >= '{$since}' AND unit_price > 0 AND COALESCE(prof_discount, '') <> 'NAI'
                  AND COALESCE(NULLIF(variation_id, 0), product_id) > 0
                GROUP BY pid, up
             ) s"
        );
        if (class_exists('AIEO_Price_History') && method_exists('AIEO_Price_History', 'bust_all_cache')) { AIEO_Price_History::bust_all_cache(); }
        $total = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$PH}");
        wp_send_json_success(array(
            'inserted' => (int) $inserted,
            'total'    => $total,
            'message'  => sprintf(
                
                __('✓ %1$s order-backfill rows written (previous order-backfill replaced — never duplicated). Table total across all sources: %2$s rows.', 'ai-eshop-optimizer'),
                number_format_i18n((int) $inserted),
                number_format_i18n($total)
            ),
        ));
    }

    
    public function handle_export() {
        if (!current_user_can(AIEO_CAPABILITY)) { wp_die(esc_html__('Insufficient permissions.', 'ai-eshop-optimizer')); }
        check_admin_referer('aieo_ph_export');
        if (!class_exists('AIEO_DMM_XLSX_Writer')) {
            $f = AIEO_DIR . 'includes/dmm/services/class-aieo-dmm-xlsx-writer.php';
            if (file_exists($f)) { require_once $f; }
        }
        if (!class_exists('AIEO_DMM_XLSX_Writer')) { wp_die(esc_html__('XLSX writer unavailable.', 'ai-eshop-optimizer')); }
        if (function_exists('wp_raise_memory_limit')) { wp_raise_memory_limit('admin'); }
        @set_time_limit(120); 

        global $wpdb;
        $PH     = $wpdb->prefix . 'aieo_price_history';
        $report = isset($_GET['report']) ? sanitize_key((string) wp_unslash($_GET['report'])) : 'leaders';
        if (!in_array($report, array('log', 'leaders', 'sale_not_lowest'), true)) { $report = 'leaders'; }

        if ($report === 'sale_not_lowest') {
            if (!self::is_aieo_pro_user()) { wp_die(esc_html__('This report requires the Pro version.', 'ai-eshop-optimizer')); }
            $w = new AIEO_DMM_XLSX_Writer('Sale not 30-day low');
            $w->add_header_row(array(
                __('Product', 'ai-eshop-optimizer'), __('Product ID', 'ai-eshop-optimizer'), __('SKU', 'ai-eshop-optimizer'),
                __('Current sale price', 'ai-eshop-optimizer'), __('30-day low', 'ai-eshop-optimizer'),
                __('Over by', 'ai-eshop-optimizer'), __('Low seen', 'ai-eshop-optimizer'),
            ));
            foreach ($this->query_sale_not_lowest() as $r) {
                $w->add_row(array(
                    $r['name'], (int) $r['pid'], (string) $r['sku'],
                    (float) $r['current'], (float) $r['low30'], (float) $r['gap'],
                    $r['low_at'] ? get_date_from_gmt($r['low_at'], 'Y-m-d') : '',
                ), array(1 => 'integer', 3 => 'currency', 4 => 'currency', 5 => 'currency'));
            }
            $w->stream_download('omnibus-sale-not-30day-low.xlsx');
            return;
        }

        
        
        $names = array();
        
        foreach ($wpdb->get_results("SELECT p.ID, COALESCE(NULLIF(p.post_title,''), pp.post_title) AS nm FROM {$wpdb->posts} p LEFT JOIN {$wpdb->posts} pp ON pp.ID = p.post_parent WHERE p.ID IN (SELECT DISTINCT product_id FROM {$PH})", ARRAY_A) as $nr) {
            $names[(int) $nr['ID']] = (string) $nr['nm'];
        }
        $nm = static function ($pid) use ($names) {
            $pid = (int) $pid;
            return (isset($names[$pid]) && $names[$pid] !== '') ? $names[$pid] : ('#' . $pid);
        };

        if ($report === 'log') {
            $w = new AIEO_DMM_XLSX_Writer('Price-change log');
            $w->add_header_row(array(
                __('Product', 'ai-eshop-optimizer'), __('Product ID', 'ai-eshop-optimizer'),
                __('Date', 'ai-eshop-optimizer'), __('Price', 'ai-eshop-optimizer'),
                __('On sale', 'ai-eshop-optimizer'), __('Source', 'ai-eshop-optimizer'),
            ));
            
            foreach ($wpdb->get_results("SELECT product_id, observed_at, price, on_sale, source FROM {$PH} ORDER BY product_id, observed_at", ARRAY_A) as $r) {
                $w->add_row(array(
                    $nm($r['product_id']), (int) $r['product_id'],
                    get_date_from_gmt($r['observed_at'], 'Y-m-d H:i'),
                    (float) $r['price'],
                    $r['on_sale'] ? __('Yes', 'ai-eshop-optimizer') : '',
                    (string) $r['source'],
                ), array(1 => 'integer', 3 => 'currency'));
            }
            $w->stream_download('price-history-change-log.xlsx');
        } else {
            $w = new AIEO_DMM_XLSX_Writer('Most price changes');
            $w->add_header_row(array(
                '#', __('Product', 'ai-eshop-optimizer'), __('Product ID', 'ai-eshop-optimizer'),
                __('Price changes', 'ai-eshop-optimizer'), __('First', 'ai-eshop-optimizer'),
                __('Last', 'ai-eshop-optimizer'), __('Lowest', 'ai-eshop-optimizer'), __('Highest', 'ai-eshop-optimizer'),
            ));
            $rank = 0;
            
            foreach ($wpdb->get_results("SELECT product_id, COUNT(*) changes, MIN(observed_at) first_at, MAX(observed_at) last_at, MIN(price) lo, MAX(price) hi FROM {$PH} GROUP BY product_id ORDER BY changes DESC, last_at DESC", ARRAY_A) as $r) {
                $rank++;
                $w->add_row(array(
                    $rank, $nm($r['product_id']), (int) $r['product_id'], (int) $r['changes'],
                    get_date_from_gmt($r['first_at'], 'Y-m-d'), get_date_from_gmt($r['last_at'], 'Y-m-d'),
                    (float) $r['lo'], (float) $r['hi'],
                ), array(0 => 'integer', 2 => 'integer', 3 => 'integer', 6 => 'currency', 7 => 'currency'));
            }
            $w->stream_download('price-history-most-changes.xlsx');
        }
    }

    
    
    

    public function render_subtab() {
        $s      = $this->settings();
        $nonce  = wp_create_nonce(AIEO_DMM::NONCE_ACTION);
        $ajax   = admin_url('admin-ajax.php');
        $pid    = isset($_GET['ph_product']) ? absint($_GET['ph_product']) : 0;
        $base_url = add_query_arg(array('page' => AIEO_DMM::MENU_SLUG, 'dmm_tab' => $this->get_id()), admin_url('admin.php'));

        
        
        $next_ts = wp_next_scheduled(self::CRON_HOOK);
        global $wpdb;
        $ph_table  = $wpdb->prefix . 'aieo_price_history';
        $row_count = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$ph_table}"); 
        $last_obs  = $wpdb->get_var("SELECT MAX(observed_at) FROM {$ph_table}"); 
        $by_source = $wpdb->get_results("SELECT source, COUNT(*) c FROM {$ph_table} GROUP BY source ORDER BY c DESC", ARRAY_A); 
        ?>
        <div class="aieo-dmm-section">
            <h2><?php esc_html_e('Price History (EU Omnibus)', 'ai-eshop-optimizer'); ?></h2>
            <p class="description" style="max-width:880px;">
                <?php esc_html_e('Records every product’s effective sell price over time (change-only — one row per actual price change, kept permanently) and resolves the lowest price of the last 30 days. This is the legally-required “prior price” for any advertised reduction (Price Indication Directive 98/6/EC as amended by the Omnibus Directive 2019/2161, GR Law 4933/2022). The on-sale lowest-price message + the discount % are computed against this 30-day low instead of the regular price.', 'ai-eshop-optimizer'); ?>
            </p>

            <form id="aieo-ph-form" class="aieo-dmm-card" style="margin:14px 0;padding:16px;border:1px solid #c3c4c7;background:#fff;max-width:880px;">
                <label style="display:block;margin-bottom:8px;">
                    <input type="checkbox" name="enabled" value="1" <?php checked(!empty($s['enabled'])); ?>>
                    <strong><?php esc_html_e('Record price history + use the 30-day low for the Omnibus reference', 'ai-eshop-optimizer'); ?></strong>
                </label>
                <p class="description" style="margin:0 0 10px;"><?php esc_html_e('On by default — this is a compliance feature. When off, capture stops and the lowest-price message falls back to the regular price.', 'ai-eshop-optimizer'); ?></p>
                <button type="submit" class="button button-primary" id="aieo-ph-save" style="display:block;width:100%;box-sizing:border-box;text-align:center;margin-top:4px;"><?php esc_html_e('Save', 'ai-eshop-optimizer'); ?></button>
                <button type="button" class="button" id="aieo-ph-snapshot" style="display:block;width:100%;box-sizing:border-box;text-align:center;margin-top:8px;"><?php esc_html_e('Snapshot prices now', 'ai-eshop-optimizer'); ?></button>
                <span id="aieo-ph-status" style="margin-left:12px;font-weight:600;"></span>
            </form>

            <?php
            
            
            $stored_raw = get_option(self::OPTION_KEY, array());
            $live_sched = wp_get_schedule(self::CRON_HOOK); 
            $freq = isset($stored_raw['frequency']) ? $stored_raw['frequency'] : ($live_sched === 'hourly' ? 'hourly' : 'daily');
            $time = isset($stored_raw['time']) ? $stored_raw['time'] : ($next_ts > 0 ? wp_date('H:i', $next_ts) : '03:30');
            ?>
            <div class="aieo-dmm-card" style="margin:14px 0;padding:16px;border:1px solid #c3c4c7;background:#fff;max-width:880px;">
                <h3 style="margin-top:0;"><?php esc_html_e('Automatic capture schedule', 'ai-eshop-optimizer'); ?></h3>
                <p class="description" style="margin:0 0 10px;"><?php esc_html_e('The change-only sweep that records the daily prices — a safety net for scheduled sales that bypass the save hook. Managed here in the plugin (no WP-Cron tool needed).', 'ai-eshop-optimizer'); ?></p>
                <p>
                    <label style="margin-right:18px;"><input type="radio" name="aieo-ph-freq" value="off" <?php checked('off', $freq); ?>> <?php esc_html_e('Off (manual only)', 'ai-eshop-optimizer'); ?></label>
                    <label style="margin-right:18px;"><input type="radio" name="aieo-ph-freq" value="hourly" <?php checked('hourly', $freq); ?>> <?php esc_html_e('Every hour', 'ai-eshop-optimizer'); ?></label>
                    <label style="margin-right:18px;"><input type="radio" name="aieo-ph-freq" value="daily" <?php checked('daily', $freq); ?>> <?php esc_html_e('Daily at', 'ai-eshop-optimizer'); ?>
                        <input type="time" id="aieo-ph-time" value="<?php echo esc_attr($time); ?>" style="width:110px;"> <span style="color:#6b7280;"><?php esc_html_e('(Europe/Athens)', 'ai-eshop-optimizer'); ?></span></label>
                </p>
                <p>
                    <button type="button" class="button button-primary" id="aieo-ph-sched-save"><?php esc_html_e('Save schedule', 'ai-eshop-optimizer'); ?></button>
                    <button type="button" class="button" id="aieo-ph-run" style="margin-left:8px;"><?php esc_html_e('Run now', 'ai-eshop-optimizer'); ?></button>
                </p>
                <p style="margin:8px 0 0;font-size:12px;color:#374151;">
                    <strong><?php esc_html_e('Next scheduled run:', 'ai-eshop-optimizer'); ?></strong>
                    <span id="aieo-ph-next"><?php
                        if ($next_ts > 0) { echo esc_html(human_time_diff($next_ts) . ' (' . wp_date('Y-m-d H:i', $next_ts) . ')'); }
                        else { esc_html_e('not scheduled', 'ai-eshop-optimizer'); }
                    ?></span>
                    <?php if ($row_count > 0) {
                        echo ' &middot; <strong>' . esc_html(number_format_i18n($row_count)) . '</strong> ' . esc_html__('price-change rows recorded', 'ai-eshop-optimizer');
                        if ($last_obs) { echo ' &middot; ' . esc_html__('last change', 'ai-eshop-optimizer') . ' ' . esc_html(get_date_from_gmt($last_obs, 'Y-m-d H:i')); }
                    } ?>
                </p>
            </div>

            <div class="aieo-dmm-card" style="margin:14px 0;padding:16px;border:1px solid #c3c4c7;background:#fff;max-width:880px;">
                <h3 style="margin-top:0;"><?php esc_html_e('Backfill from order history (dry-run)', 'ai-eshop-optimizer'); ?></h3>
                <p class="description" style="margin:0 0 10px;"><?php esc_html_e('Reconstructs each product’s price timeline from past orders (from the start date below) using AIEO’s precomputed order-products analytics: the distinct unit prices each product was actually sold at, and the earliest date each appeared. Professional / role-priced lines are excluded via the precomputed prof-discount flag (not a hardcoded role list); sale prices are kept (they are the Omnibus “lowest price applied”). Read-only — counts the distinct prices, writes nothing.', 'ai-eshop-optimizer'); ?></p>
                <p style="margin:0 0 10px;">
                    <label><strong><?php esc_html_e('Backfill from:', 'ai-eshop-optimizer'); ?></strong>
                        <input type="date" id="aieo-ph-since" value="<?php echo esc_attr($this->backfill_since_setting()); ?>" style="margin-left:6px;"></label>
                    <span class="description" style="margin-left:8px;"><?php esc_html_e('Move this forward if the order history grows huge.', 'ai-eshop-optimizer'); ?></span>
                </p>
                <p>
                    <button type="button" class="button button-secondary" id="aieo-ph-scan"><?php esc_html_e('Scan order history (dry-run)', 'ai-eshop-optimizer'); ?></button>
                    <button type="button" class="button button-primary" id="aieo-ph-scan-save" style="margin-left:8px;"><?php esc_html_e('Save to price-history', 'ai-eshop-optimizer'); ?></button>
                    <span id="aieo-ph-scan-status" style="margin-left:10px;color:#646970;font-size:13px;"></span>
                </p>
                <div id="aieo-ph-scan-bar-wrap" style="display:none;height:18px;background:#e5e7eb;border-radius:9px;overflow:hidden;max-width:600px;margin:6px 0;">
                    <div id="aieo-ph-scan-bar" style="height:100%;width:0;background:#2271b1;transition:width .25s;"></div>
                </div>
                <p id="aieo-ph-scan-result" style="margin:8px 0 0;font-weight:600;color:#15803d;"></p>
                <p style="margin:10px 0 0;font-size:12px;color:#374151;border-top:1px solid #eee;padding-top:8px;">
                    <strong><?php esc_html_e('Price-history table:', 'ai-eshop-optimizer'); ?></strong>
                    <?php
                    $src_labels = array(
                        'order_backfill'    => __('order backfill (2022→)', 'ai-eshop-optimizer'),
                        'backfill'          => __('baseline snapshot', 'ai-eshop-optimizer'),
                        'cron_snapshot'     => __('nightly sweeps', 'ai-eshop-optimizer'),
                        'price_change_hook' => __('live captures', 'ai-eshop-optimizer'),
                    );
                    $parts = array();
                    foreach ((array) $by_source as $bs) {
                        $lbl = isset($src_labels[$bs['source']]) ? $src_labels[$bs['source']] : (string) $bs['source'];
                        $parts[] = '<strong>' . esc_html(number_format_i18n((int) $bs['c'])) . '</strong> ' . esc_html($lbl);
                    }
                    echo $parts ? wp_kses_post(implode(' &middot; ', $parts)) . ' = <strong>' . esc_html(number_format_i18n($row_count)) . '</strong> ' . esc_html__('rows total (across all sources)', 'ai-eshop-optimizer') : esc_html__('empty', 'ai-eshop-optimizer');
                    ?>
                </p>
            </div>

            <div id="aieo-ph-pick-wrap" style="margin:18px 0;max-width:880px;">
                <?php
                if (class_exists('AIEO_DMM_Product_Picker')) {
                    echo AIEO_DMM_Product_Picker::render_field(array(  
                        'name'     => 'ph_product_pick',
                        'label'    => __('Price-history chart — choose a product', 'ai-eshop-optimizer'),
                        'help'     => __('Search by name or SKU and pick ONE product (or a specific variation) to chart its 30-day price history. No need to know the ID.', 'ai-eshop-optimizer'),
                        'button'   => __('🔍 Search / choose a product', 'ai-eshop-optimizer'),
                        'selected' => $pid ? array($pid) : array(),
                    ));
                }
                ?>
                <button type="button" class="button button-secondary" id="aieo-ph-show" style="margin-top:6px;"><?php esc_html_e('Show history', 'ai-eshop-optimizer'); ?></button>
            </div>
            <script>
            (function () {
                var btn = document.getElementById('aieo-ph-show');
                if (!btn) { return; }
                var base = <?php echo wp_json_encode($base_url); ?>;
                btn.addEventListener('click', function () {
                    var store = document.querySelector('#aieo-ph-pick-wrap select.aieo-prodpick-store');
                    var pid = '';
                    if (store) { for (var i = 0; i < store.options.length; i++) { if (store.options[i].selected && store.options[i].value) { pid = store.options[i].value; break; } } }
                    if (!pid && store && store.options.length) { pid = store.options[0].value; }
                    if (pid) { window.location.href = base + '&ph_product=' + encodeURIComponent(pid); }
                    else { window.alert(<?php echo wp_json_encode(__('Search and pick a product first.', 'ai-eshop-optimizer')); ?>); }
                });
            })();
            </script>

            <?php if ($pid > 0) { $this->render_product_history($pid); } ?>

            <?php $this->render_reports(); ?>
            <?php $this->render_omnibus_compliance_report(); ?>
        </div>
        <script>
        (function () {
            var f = document.getElementById('aieo-ph-form');
            var st = document.getElementById('aieo-ph-status');
            var ajax = <?php echo wp_json_encode($ajax); ?>, nonce = <?php echo wp_json_encode($nonce); ?>;
            function post(action, extra, done) {
                var fd = new FormData(); fd.append('action', action); fd.append('nonce', nonce);
                if (extra) { for (var k in extra) fd.append(k, extra[k]); }
                if (st) { st.style.color = '#6b7280'; st.textContent = <?php echo wp_json_encode(__('Working…', 'ai-eshop-optimizer')); ?>; }
                fetch(ajax, { method:'POST', credentials:'same-origin', body: fd }).then(function(r){return r.json();}).then(function(j){
                    if (st) { st.style.color = (j && j.success) ? '#15803d' : '#b91c1c'; st.textContent = (j && j.data && j.data.message) ? j.data.message : (j && j.success ? 'OK' : 'Error'); }
                    if (done) done(j);
                }).catch(function(){ if (st){ st.style.color='#b91c1c'; st.textContent='Network error.'; } });
            }
            if (f) f.addEventListener('submit', function(e){ e.preventDefault(); post('aieo_price_history_save', { enabled: f.querySelector('[name=enabled]').checked ? 1 : 0 }); });
            var snap = document.getElementById('aieo-ph-snapshot');
            if (snap) snap.addEventListener('click', function(){ post('aieo_price_history_backfill', {}); });
            var schedSave = document.getElementById('aieo-ph-sched-save');
            if (schedSave) schedSave.addEventListener('click', function(){
                var freq = (document.querySelector('input[name=aieo-ph-freq]:checked') || {}).value || 'daily';
                var time = (document.getElementById('aieo-ph-time') || {}).value || '03:30';
                post('aieo_price_history_save', { frequency: freq, time: time }, function(j){
                    if (j && j.success && j.data && j.data.next_human) {
                        var nx = document.getElementById('aieo-ph-next'); if (nx) nx.textContent = j.data.next_human;
                    }
                });
            });
            var runNow = document.getElementById('aieo-ph-run');
            if (runNow) runNow.addEventListener('click', function(){ post('aieo_price_history_backfill', {}); });

            var scanBtn = document.getElementById('aieo-ph-scan');
            if (scanBtn) scanBtn.addEventListener('click', function(){
                var sst = document.getElementById('aieo-ph-scan-status'),
                    barWrap = document.getElementById('aieo-ph-scan-bar-wrap'),
                    bar = document.getElementById('aieo-ph-scan-bar'),
                    res = document.getElementById('aieo-ph-scan-result');
                scanBtn.disabled = true; if (res) res.textContent = '';
                if (barWrap) barWrap.style.display = 'block';
                var totalPrices = 0;
                function call(extra){
                    var fd = new FormData(); fd.append('action', 'aieo_price_history_orderscan'); fd.append('nonce', nonce);
                    var _since=(document.getElementById('aieo-ph-since')||{}).value||''; if(_since) fd.append('since', _since);
                    for (var k in extra) { fd.append(k, extra[k]); }
                    return fetch(ajax, { method:'POST', credentials:'same-origin', body: fd }).then(function(r){ return r.json(); });
                }
                call({ mode: 'init' }).then(function(j){
                    if (!j || !j.success) { if (sst) sst.textContent = (j && j.data && j.data.message) ? j.data.message : 'Init failed'; scanBtn.disabled = false; return; }
                    var total = j.data.total, offset = 0;
                    if (sst) sst.textContent = total.toLocaleString() + ' products to evaluate…';
                    (function step(){
                        call({ mode: 'batch', offset: offset }).then(function(b){
                            if (!b || !b.success) { if (sst) sst.textContent = (b && b.data && b.data.message) ? b.data.message : 'Batch failed'; scanBtn.disabled = false; return; }
                            totalPrices += (b.data.batch_prices || 0);
                            offset = b.data.processed;
                            var pct = total > 0 ? Math.round(offset / total * 100) : 100;
                            if (bar) bar.style.width = pct + '%';
                            if (sst) sst.textContent = offset.toLocaleString() + ' / ' + total.toLocaleString() + ' products · ' + totalPrices.toLocaleString() + ' distinct prices so far';
                            if (b.data.done) {
                                if (res) res.textContent = '✓ ' + totalPrices.toLocaleString() + ' distinct order-based prices across ' + offset.toLocaleString() + ' products — this is exactly what “Save to price-history” writes (source: order_backfill). The full table also keeps the baseline + nightly + live rows (see the breakdown below).';
                                scanBtn.disabled = false;
                            } else { step(); }
                        });
                    })();
                });
            });

            var saveBtn = document.getElementById('aieo-ph-scan-save');
            if (saveBtn) saveBtn.addEventListener('click', function(){
                if (!window.confirm(<?php echo wp_json_encode(__('Write the backfilled prices into the price-history table? Any previous order-backfill rows are replaced first.', 'ai-eshop-optimizer')); ?>)) { return; }
                var res = document.getElementById('aieo-ph-scan-result');
                saveBtn.disabled = true;
                if (res) { res.style.color = '#6b7280'; res.textContent = <?php echo wp_json_encode(__('Writing…', 'ai-eshop-optimizer')); ?>; }
                var fd = new FormData(); fd.append('action', 'aieo_price_history_ordersave'); fd.append('nonce', nonce);
                var _since=(document.getElementById('aieo-ph-since')||{}).value||''; if(_since) fd.append('since', _since);
                fetch(ajax, { method:'POST', credentials:'same-origin', body: fd }).then(function(r){ return r.json(); }).then(function(j){
                    if (res) { res.style.color = (j && j.success) ? '#15803d' : '#b91c1c'; res.textContent = (j && j.data && j.data.message) ? j.data.message : (j && j.success ? 'Saved' : 'Error'); }
                    saveBtn.disabled = false;
                }).catch(function(){ if (res) { res.style.color = '#b91c1c'; res.textContent = 'Network error.'; } saveBtn.disabled = false; });
            });
        })();
        </script>
        <?php
    }

    
    private function render_reports() {
        global $wpdb;
        $PH = $wpdb->prefix . 'aieo_price_history';
        $leaders = $wpdb->get_results(
            "SELECT product_id, COUNT(*) AS changes, MIN(observed_at) AS first_at, MAX(observed_at) AS last_at, MIN(price) AS lo, MAX(price) AS hi
             FROM {$PH} GROUP BY product_id ORDER BY changes DESC, last_at DESC LIMIT 50",
            ARRAY_A
        );
        if (empty($leaders)) { return; }

        $name = static function ($pid) {
            $p = function_exists('wc_get_product') ? wc_get_product((int) $pid) : null;
            if ($p) { return $p->get_name(); }
            $t = get_the_title((int) $pid);
            return $t !== '' ? $t : ('#' . (int) $pid);
        };
        $money = static function ($v) {
            return function_exists('wc_price') ? wc_price((float) $v) : esc_html(number_format((float) $v, 2));
        };
        $export = static function ($report) {
            return wp_nonce_url(admin_url('admin-post.php?action=aieo_ph_export&report=' . $report), 'aieo_ph_export');
        };

        echo '<div class="aieo-dmm-section" style="margin-top:24px;">';
        echo '<h2>' . esc_html__('Reports', 'ai-eshop-optimizer') . '</h2>';

        
        echo '<h3>' . esc_html__('Products with the most price changes', 'ai-eshop-optimizer')
            . ' <a class="button button-small" style="font-weight:400;vertical-align:middle;" href="' . esc_url($export('leaders')) . '">' . esc_html__('⬇ Export XLSX (all)', 'ai-eshop-optimizer') . '</a></h3>';
        echo '<table class="widefat striped" style="max-width:980px;"><thead><tr>';
        foreach (array('#', __('Product', 'ai-eshop-optimizer'), __('Changes', 'ai-eshop-optimizer'), __('First', 'ai-eshop-optimizer'), __('Last', 'ai-eshop-optimizer'), __('Lowest', 'ai-eshop-optimizer'), __('Highest', 'ai-eshop-optimizer')) as $h) {
            echo '<th>' . esc_html($h) . '</th>';
        }
        echo '</tr></thead><tbody>';
        $rank = 0;
        foreach ($leaders as $r) {
            $rank++;
            echo '<tr>';
            echo '<td>' . (int) $rank . '</td>';
            echo '<td>' . esc_html($name($r['product_id'])) . ' <span style="color:#9ca3af;">#' . (int) $r['product_id'] . '</span></td>';
            echo '<td><strong>' . (int) $r['changes'] . '</strong></td>';
            echo '<td>' . esc_html(get_date_from_gmt($r['first_at'], 'Y-m-d')) . '</td>';
            echo '<td>' . esc_html(get_date_from_gmt($r['last_at'], 'Y-m-d')) . '</td>';
            echo '<td>' . wp_kses_post($money($r['lo'])) . '</td>';
            echo '<td>' . wp_kses_post($money($r['hi'])) . '</td>';
            echo '</tr>';
        }
        echo '</tbody></table>';

        
        $top_ids = array_slice(array_map(static function ($r) { return (int) $r['product_id']; }, $leaders), 0, 25);
        $in      = implode(',', array_map('intval', $top_ids));
        $rows    = $wpdb->get_results(
            "SELECT product_id, observed_at, price, on_sale, source FROM {$PH} WHERE product_id IN ({$in}) ORDER BY observed_at ASC",
            ARRAY_A
        );
        $rank_of = array_flip($top_ids);
        usort($rows, static function ($a, $b) use ($rank_of) {
            $ra = $rank_of[(int) $a['product_id']];
            $rb = $rank_of[(int) $b['product_id']];
            return ($ra !== $rb) ? ($ra - $rb) : strcmp((string) $a['observed_at'], (string) $b['observed_at']);
        });

        echo '<h3 style="margin-top:22px;">' . esc_html__('Price-change log — top 25 movers (unpivoted)', 'ai-eshop-optimizer')
            . ' <a class="button button-small" style="font-weight:400;vertical-align:middle;" href="' . esc_url($export('log')) . '">' . esc_html__('⬇ Export XLSX (full log)', 'ai-eshop-optimizer') . '</a></h3>';
        echo '<p class="description">' . esc_html__('One row per price change. Products with the most changes first, then chronological.', 'ai-eshop-optimizer') . '</p>';
        echo '<table class="widefat striped" style="max-width:980px;"><thead><tr>';
        foreach (array(__('Product', 'ai-eshop-optimizer'), __('Date', 'ai-eshop-optimizer'), __('Price', 'ai-eshop-optimizer'), __('On sale', 'ai-eshop-optimizer'), __('Source', 'ai-eshop-optimizer')) as $h) {
            echo '<th>' . esc_html($h) . '</th>';
        }
        echo '</tr></thead><tbody>';
        $names = array();
        foreach ($rows as $r) {
            $pid = (int) $r['product_id'];
            if (!isset($names[$pid])) { $names[$pid] = $name($pid); }
            echo '<tr>';
            echo '<td>' . esc_html($names[$pid]) . ' <span style="color:#9ca3af;">#' . $pid . '</span></td>';
            echo '<td>' . esc_html(get_date_from_gmt($r['observed_at'], 'Y-m-d H:i')) . '</td>';
            echo '<td>' . wp_kses_post($money($r['price'])) . '</td>';
            echo '<td>' . ($r['on_sale'] ? esc_html__('Yes', 'ai-eshop-optimizer') : '—') . '</td>';
            echo '<td><code style="font-size:11px;">' . esc_html((string) $r['source']) . '</code></td>';
            echo '</tr>';
        }
        echo '</tbody></table>';
        echo '</div>';
    }

    
    private function query_sale_not_lowest() {
        global $wpdb;
        $PH = $wpdb->prefix . 'aieo_price_history';
        if ((string) $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $PH)) !== $PH) { return array(); }
        $since30 = gmdate('Y-m-d H:i:s', time() - 30 * DAY_IN_SECONDS);
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT t1.product_id AS pid, t1.price AS current_price, low.low30 AS low30
             FROM {$PH} t1
             INNER JOIN (SELECT product_id, MAX(observed_at) AS mx FROM {$PH} GROUP BY product_id) t2
               ON t2.product_id = t1.product_id AND t2.mx = t1.observed_at
             INNER JOIN (SELECT product_id, MIN(price) AS low30 FROM {$PH} WHERE observed_at >= %s GROUP BY product_id) low
               ON low.product_id = t1.product_id
             WHERE t1.on_sale = 1 AND t1.price > low.low30 + 0.005
             ORDER BY (t1.price - low.low30) DESC",
            $since30
        ), ARRAY_A);
        if (empty($rows)) { return array(); }
        $in = implode(',', array_map(static function ($r) { return (int) $r['pid']; }, $rows));
        $names = array(); $skus = array();
        
        foreach ($wpdb->get_results("SELECT p.ID, COALESCE(NULLIF(p.post_title,''), pp.post_title) AS nm FROM {$wpdb->posts} p LEFT JOIN {$wpdb->posts} pp ON pp.ID = p.post_parent WHERE p.ID IN ({$in})", ARRAY_A) as $nr) { $names[(int) $nr['ID']] = (string) $nr['nm']; }
        
        foreach ($wpdb->get_results("SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = '_sku' AND post_id IN ({$in})", ARRAY_A) as $sr) { $skus[(int) $sr['post_id']] = (string) $sr['meta_value']; }
        $out = array();
        foreach ($rows as $r) {
            $pid = (int) $r['pid']; $cur = (float) $r['current_price']; $low = (float) $r['low30'];
            
            $low_at = $wpdb->get_var($wpdb->prepare("SELECT MIN(observed_at) FROM {$PH} WHERE product_id = %d AND observed_at >= %s AND price = %f", $pid, $since30, $low));
            $out[] = array(
                'pid'     => $pid,
                'name'    => (isset($names[$pid]) && $names[$pid] !== '') ? $names[$pid] : ('#' . $pid),
                'sku'     => isset($skus[$pid]) ? $skus[$pid] : '',
                'current' => $cur, 'low30' => $low, 'gap' => $cur - $low, 'low_at' => $low_at,
            );
        }
        return $out;
    }

    
    private function render_omnibus_compliance_report() {
        echo '<div class="aieo-dmm-section" style="margin-top:28px;">';
        echo '<h2>' . esc_html__('Omnibus compliance — sale price isn’t the 30-day low', 'ai-eshop-optimizer') . '</h2>';
        if (!self::is_aieo_pro_user()) {
            $this->render_report_pro_lock();
            echo '</div>';
            return;
        }
        $rows   = $this->query_sale_not_lowest();
        $export = wp_nonce_url(admin_url('admin-post.php?action=aieo_ph_export&report=sale_not_lowest'), 'aieo_ph_export');
        echo '<p class="description" style="max-width:880px;">' . esc_html__('Products currently on sale whose sale price is higher than their lowest price in the last 30 days — the advertised reduction is NOT against the genuine 30-day low (Omnibus risk). Lower the sale price to the 30-day low, or wait out the window, for each.', 'ai-eshop-optimizer') . '</p>';
        echo '<p><a class="button button-small" href="' . esc_url($export) . '">' . esc_html__('⬇ Export XLSX', 'ai-eshop-optimizer') . '</a></p>';
        if (empty($rows)) {
            echo '<p style="color:#15803d;font-weight:600;">' . esc_html__('✓ Every on-sale product is priced at or below its 30-day low. Nothing to fix.', 'ai-eshop-optimizer') . '</p></div>';
            return;
        }
        $money = static function ($v) { return function_exists('wc_price') ? wc_price((float) $v) : esc_html(number_format((float) $v, 2)); };
        echo '<table class="widefat striped" style="max-width:980px;"><thead><tr>';
        foreach (array('#', __('Product', 'ai-eshop-optimizer'), __('SKU', 'ai-eshop-optimizer'), __('Current sale price', 'ai-eshop-optimizer'), __('30-day low', 'ai-eshop-optimizer'), __('Over by', 'ai-eshop-optimizer'), __('Low seen', 'ai-eshop-optimizer')) as $h) { echo '<th>' . esc_html($h) . '</th>'; }
        echo '</tr></thead><tbody>';
        $rank = 0;
        foreach ($rows as $r) {
            $rank++;
            $edit = get_edit_post_link($r['pid']);
            echo '<tr>';
            echo '<td>' . (int) $rank . '</td>';
            echo '<td>' . ($edit ? '<a href="' . esc_url($edit) . '">' . esc_html($r['name']) . '</a>' : esc_html($r['name'])) . ' <span style="color:#9ca3af;">#' . (int) $r['pid'] . '</span></td>';
            echo '<td>' . esc_html($r['sku']) . '</td>';
            echo '<td>' . wp_kses_post($money($r['current'])) . '</td>';
            echo '<td>' . wp_kses_post($money($r['low30'])) . '</td>';
            echo '<td style="color:#b91c1c;font-weight:600;">' . wp_kses_post($money($r['gap'])) . '</td>';
            echo '<td>' . ($r['low_at'] ? esc_html(get_date_from_gmt($r['low_at'], 'Y-m-d')) : '—') . '</td>';
            echo '</tr>';
        }
        echo '</tbody></table></div>';
    }

    
    private function render_report_pro_lock() {
        self::print_pro_overlay_styles();
        echo '<div class="aieo-dmm-pro-locked-wrapper aieo-pro-locked">';
        echo '<div class="aieo-dmm-pro-placeholder" aria-hidden="true">';
        for ($i = 0; $i < 3; $i++) {
            echo '<div class="aieo-dmm-pro-placeholder-card"><div class="aieo-dmm-pro-placeholder-line"></div><div class="aieo-dmm-pro-placeholder-line short"></div><div class="aieo-dmm-pro-placeholder-line"></div></div>';
        }
        echo '</div>';
        echo '<div class="aieo-pro-overlay"><div class="aieo-pro-overlay-content">';
        echo '<div class="aieo-pro-badge"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M5 16L3 5L8.5 10L12 4L15.5 10L21 5L19 16H5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg><span>' . esc_html__('PRO', 'ai-eshop-optimizer') . '</span></div>';
        echo '<h3>' . esc_html__('Omnibus compliance report', 'ai-eshop-optimizer') . '</h3>';
        echo '<p>' . esc_html__('See exactly which on-sale products break the EU Omnibus rule — their sale price isn’t the genuine 30-day low — so you can fix non-compliant reductions before they cost you a fine. One-click XLSX export included.', 'ai-eshop-optimizer') . '</p>';
        echo '<a href="https://rooster.systems/get-aieo/" target="_blank" rel="noopener noreferrer" class="aieo-pro-overlay-button">' . esc_html__('Upgrade to Pro', 'ai-eshop-optimizer') . ' →</a>';
        echo '</div></div></div>';
    }

    
    private function render_product_history($product_id) {
        $product = function_exists('wc_get_product') ? wc_get_product($product_id) : null;
        if (!$product) {
            echo '<div class="notice notice-error inline"><p>' . esc_html__('Product not found.', 'ai-eshop-optimizer') . '</p></div>';
            return;
        }
        $history = AIEO_Price_History::history($product_id);
        $ref     = AIEO_Price_History::reference($product_id);
        $low30   = AIEO_Price_History::lowest_30d($product_id);

        echo '<div class="aieo-dmm-card" style="padding:18px;border:1px solid #c3c4c7;background:#fff;max-width:880px;">';
        echo '<h3 style="margin-top:0;">' . esc_html($product->get_name()) . ' <span style="color:#646970;font-weight:400;">#' . (int) $product_id . '</span></h3>';

        echo '<p style="margin:0 0 12px;">';
        echo '<strong>' . esc_html__('Current price:', 'ai-eshop-optimizer') . '</strong> ' . wp_kses_post(wc_price((float) $product->get_price())) . ' &nbsp;·&nbsp; ';
        echo '<strong>' . esc_html__('30-day low:', 'ai-eshop-optimizer') . '</strong> ' . ($low30 !== null ? wp_kses_post(wc_price($low30)) : '—');
        if ($ref) {
            echo ' &nbsp;·&nbsp; <span style="color:#b91c1c;font-weight:600;">' . sprintf(
                
                esc_html__('Reduction: −%d%% vs the 30-day low', 'ai-eshop-optimizer'),
                (int) $ref['discount_pct']
            ) . '</span>';
        } else {
            echo ' &nbsp;·&nbsp; <span style="color:#646970;">' . esc_html__('Not a reduction (no Omnibus reference shown)', 'ai-eshop-optimizer') . '</span>';
        }
        echo '</p>';

        $this->render_chart($history, $low30);

        
        echo '<table class="widefat striped" style="margin-top:14px;">';
        echo '<thead><tr><th>' . esc_html__('Observed (UTC)', 'ai-eshop-optimizer') . '</th><th style="text-align:right;">' . esc_html__('Price', 'ai-eshop-optimizer') . '</th><th style="text-align:right;">' . esc_html__('Regular', 'ai-eshop-optimizer') . '</th><th>' . esc_html__('On sale', 'ai-eshop-optimizer') . '</th><th>' . esc_html__('Source', 'ai-eshop-optimizer') . '</th></tr></thead><tbody>';
        if (empty($history)) {
            echo '<tr><td colspan="5"><em>' . esc_html__('No history yet — save the product or run “Snapshot prices now”.', 'ai-eshop-optimizer') . '</em></td></tr>';
        } else {
            foreach (array_reverse($history) as $r) {
                echo '<tr>';
                echo '<td>' . esc_html((string) $r['observed_at']) . '</td>';
                echo '<td style="text-align:right;">' . wp_kses_post(wc_price((float) $r['price'])) . '</td>';
                echo '<td style="text-align:right;">' . ($r['regular_price'] !== null ? wp_kses_post(wc_price((float) $r['regular_price'])) : '—') . '</td>';
                echo '<td>' . ((int) $r['on_sale'] ? '✅' : '—') . '</td>';
                echo '<td><code style="font-size:11px;">' . esc_html((string) $r['source']) . '</code></td>';
                echo '</tr>';
            }
        }
        echo '</tbody></table>';
        echo '</div>';
    }

    
    private function render_chart($history, $low30) {
        if (empty($history)) { return; }

        $W = 820; $H = 280; $padL = 64; $padR = 18; $padT = 18; $padB = 40;
        $pts = array();
        foreach ($history as $r) {
            $pts[] = array('t' => (int) strtotime($r['observed_at'] . ' UTC'), 'p' => (float) $r['price']);
        }
        
        $last = end($pts);
        $pts[] = array('t' => time(), 'p' => $last['p']);

        $tMin = $pts[0]['t']; $tMax = end($pts)['t'];
        if ($tMax <= $tMin) { $tMax = $tMin + DAY_IN_SECONDS; }
        $prices = array();
        foreach ($pts as $pt) { $prices[] = $pt['p']; }
        if ($low30 !== null) { $prices[] = (float) $low30; }
        $pMin = min($prices); $pMax = max($prices);
        if ($pMax <= $pMin) { $pMax = $pMin + 1; }
        $padY = ($pMax - $pMin) * 0.12;
        $pMin = max(0, $pMin - $padY); $pMax += $padY;

        $plotW = $W - $padL - $padR; $plotH = $H - $padT - $padB;
        $fx = function ($t) use ($tMin, $tMax, $padL, $plotW) { return $padL + ($t - $tMin) / ($tMax - $tMin) * $plotW; };
        $fy = function ($p) use ($pMin, $pMax, $padT, $plotH) { return $padT + ($pMax - $p) / ($pMax - $pMin) * $plotH; };

        
        $d = '';
        foreach ($pts as $i => $pt) {
            $x = round($fx($pt['t']), 1); $y = round($fy($pt['p']), 1);
            if ($i === 0) { $d .= 'M' . $x . ' ' . $y; }
            else { $py = round($fy($pts[$i - 1]['p']), 1); $d .= ' L' . $x . ' ' . $py . ' L' . $x . ' ' . $y; }
        }

        $cur_sym = function_exists('get_woocommerce_currency_symbol') ? get_woocommerce_currency_symbol() : '';
        $ylab = function ($p) use ($cur_sym) { return $cur_sym . number_format((float) $p, 2); };

        echo '<svg viewBox="0 0 ' . (int) $W . ' ' . (int) $H . '" width="100%" style="max-width:' . (int) $W . 'px;height:auto;font-family:inherit;">';
        
        for ($g = 0; $g <= 4; $g++) {
            $pv = $pMin + ($pMax - $pMin) * $g / 4;
            $y  = round($fy($pv), 1);
            echo '<line x1="' . (int) $padL . '" y1="' . $y . '" x2="' . (int) ($W - $padR) . '" y2="' . $y . '" stroke="#e5e7eb" stroke-width="1"/>';
            echo '<text x="' . (int) ($padL - 8) . '" y="' . ($y + 4) . '" text-anchor="end" font-size="11" fill="#6b7280">' . esc_html($ylab($pv)) . '</text>';
        }
        
        echo '<text x="' . (int) $padL . '" y="' . (int) ($H - 14) . '" text-anchor="start" font-size="11" fill="#6b7280">' . esc_html(gmdate('Y-m-d', $tMin)) . '</text>';
        echo '<text x="' . (int) ($W - $padR) . '" y="' . (int) ($H - 14) . '" text-anchor="end" font-size="11" fill="#6b7280">' . esc_html__('now', 'ai-eshop-optimizer') . '</text>';
        
        if ($low30 !== null) {
            $y = round($fy((float) $low30), 1);
            echo '<line x1="' . (int) $padL . '" y1="' . $y . '" x2="' . (int) ($W - $padR) . '" y2="' . $y . '" stroke="#c82d52" stroke-width="1.5" stroke-dasharray="5 4"/>';
            echo '<text x="' . (int) ($padL + 6) . '" y="' . ($y - 5) . '" font-size="11" fill="#c82d52">' . esc_html(sprintf(__('30-day low %s', 'ai-eshop-optimizer'), $ylab($low30))) . '</text>';
        }
        
        echo '<path d="' . esc_attr($d) . '" fill="none" stroke="#1d4ed8" stroke-width="2"/>';
        foreach ($pts as $i => $pt) {
            if ($i === count($pts) - 1) { continue; } 
            echo '<circle cx="' . round($fx($pt['t']), 1) . '" cy="' . round($fy($pt['p']), 1) . '" r="3" fill="#1d4ed8"/>';
        }
        echo '</svg>';
    }
}
