<?php

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

class AIEO_Core_Brand_Vitals {

    const TABLE_NAME      = 'aieo_core_brand_vitals';
    const CACHE_GROUP     = 'aieo_core_brand_vitals';
    const CACHE_KEY_ALL   = 'all_grouped';
    const CACHE_KEY_VER   = 'version';
    const CACHE_TTL       = HOUR_IN_SECONDS;

    const DIRTY_QUEUE_OPT = 'aieo_brand_vitals_dirty_brands';

    
    private static $instance = null;

    public static function instance() {
        if (self::$instance === null) { self::$instance = new self(); }
        return self::$instance;
    }

    private function __construct() {
        
        
        
        add_action('save_post_product',          array($this, 'on_product_save'), 35, 1);
        add_action('woocommerce_update_product', array($this, 'on_product_save'), 35, 1);
        add_action('created_product_brand',      array($this, 'on_brand_term_change'), 10, 1);
        add_action('edited_product_brand',       array($this, 'on_brand_term_change'), 10, 1);
        add_action('delete_product_brand',       array($this, 'on_brand_term_change'), 10, 1);

        
        add_action('wp_ajax_aieo_brand_slider_bundle',        array($this, 'ajax_brand_slider_bundle'));
        add_action('wp_ajax_nopriv_aieo_brand_slider_bundle', array($this, 'ajax_brand_slider_bundle'));

        
        
        
        
        
        
        
        add_shortcode('aieo_brand_rails',  array($this, 'shortcode_brand_rails'));
        add_shortcode('aieo_brand_slider', array($this, 'shortcode_brand_slider'));
    }

    
    public function shortcode_brand_rails($atts = array()) {
        $atts = shortcode_atts(array(
            'show_featured'              => '1',
            'show_new'                   => '1',
            'show_favourites'            => '1',
            'show_top'                   => '0',
            'new_mode'                   => 'new_product',
            'limit_per_rail'             => '10',
            'slides_per_view'            => '5',
            'top_limit'                  => '0',
            'featured_limit'             => '0',
            'new_limit'                  => '0',
            'favourites_limit'           => '0',
            'top_slides_per_view'        => '0',
            'featured_slides_per_view'   => '0',
            'new_slides_per_view'        => '0',
            'favourites_slides_per_view' => '0',
        ), $atts, 'aieo_brand_rails');

        $to_bool = function ($v) { return in_array(strtolower((string) $v), array('1', 'true', 'yes', 'on'), true); };

        return render_block(array(
            'blockName' => 'aieo/brand-rails',
            'attrs'     => array(
                'showFeatured'           => $to_bool($atts['show_featured']),
                'showNew'                => $to_bool($atts['show_new']),
                'showFavourites'         => $to_bool($atts['show_favourites']),
                'showTop'                => $to_bool($atts['show_top']),
                'newMode'                => in_array($atts['new_mode'], array('new_product', 'new_brand'), true) ? $atts['new_mode'] : 'new_product',
                'limitPerRail'           => (int) $atts['limit_per_rail'],
                'slidesPerView'          => (int) $atts['slides_per_view'],
                'topLimit'               => (int) $atts['top_limit'],
                'featuredLimit'          => (int) $atts['featured_limit'],
                'newLimit'               => (int) $atts['new_limit'],
                'favouritesLimit'        => (int) $atts['favourites_limit'],
                'topSlidesPerView'       => (int) $atts['top_slides_per_view'],
                'featuredSlidesPerView'  => (int) $atts['featured_slides_per_view'],
                'newSlidesPerView'       => (int) $atts['new_slides_per_view'],
                'favouritesSlidesPerView'=> (int) $atts['favourites_slides_per_view'],
            ),
            'innerBlocks'  => array(),
            'innerHTML'    => '',
            'innerContent' => array(),
        ));
    }

    
    public function shortcode_brand_slider($atts = array()) {
        $atts = shortcode_atts(array(
            'mode'            => 'new_product',
            'limit'           => '10',
            'slides_per_view' => '5',
            'title'           => '',
            'subtitle'        => '',
        ), $atts, 'aieo_brand_slider');

        $valid_modes = array('top', 'featured', 'new_product', 'new_brand', 'favourites');
        $mode        = in_array($atts['mode'], $valid_modes, true) ? $atts['mode'] : 'new_product';

        $block_attrs = array(
            'mode'          => $mode,
            'limit'         => max(3, min(30, (int) $atts['limit'])),
            'slidesPerView' => max(2, min(8,  (int) $atts['slides_per_view'])),
        );
        if ($atts['title']    !== '') { $block_attrs['title']    = (string) $atts['title']; }
        if ($atts['subtitle'] !== '') { $block_attrs['subtitle'] = (string) $atts['subtitle']; }

        return render_block(array(
            'blockName'    => 'aieo/brand-slider',
            'attrs'        => $block_attrs,
            'innerBlocks'  => array(),
            'innerHTML'    => '',
            'innerContent' => array(),
        ));
    }

    public static function table() {
        global $wpdb;
        return $wpdb->prefix . self::TABLE_NAME;
    }

    public static function table_exists() {
        static $cached = null;
        if ($cached !== null) { return $cached; }
        global $wpdb;
        $found = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s",
            self::table()
        ));
        return $cached = ($found > 0);
    }

    
    
    
    

    
    public function get_all_grouped() {
        $cache_key = self::CACHE_KEY_ALL . ':' . $this->cache_version();
        $cached    = wp_cache_get($cache_key, self::CACHE_GROUP);
        if (is_array($cached)) { return $cached; }

        $out = array();
        foreach (range('A', 'Z') as $L) { $out[$L] = array('count' => 0, 'brands' => array()); }
        $out['#'] = array('count' => 0, 'brands' => array());

        if (!self::table_exists()) { return $out; }

        global $wpdb;
        $table = self::table();
        $rows = $wpdb->get_results(
            "SELECT brand_id, brand_name, brand_slug, letter, product_count, in_stock_count,
                    total_sales, hero_image_id, logo_image_id, rating_avg, rating_count,
                    promo, priority, brand_created_at, newest_product_at
               FROM {$table}
              WHERE product_count > 0
              ORDER BY letter ASC, brand_name ASC",
            ARRAY_A
        );
        if (!is_array($rows)) { return $out; }

        foreach ($rows as $r) {
            $L = isset($r['letter']) ? strtoupper((string) $r['letter']) : '#';
            if (!isset($out[$L])) { $L = '#'; }
            $out[$L]['count']++;
            $out[$L]['brands'][] = $this->shape_row($r);
        }

        wp_cache_set($cache_key, $out, self::CACHE_GROUP, self::CACHE_TTL);
        return $out;
    }

    
    public function get_top($limit = 10) {
        if (!self::table_exists()) { return array(); }
        $limit = max(1, (int) $limit);
        global $wpdb;
        $table = self::table();
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$table}
              WHERE product_count > 0
              ORDER BY total_sales DESC, product_count DESC
              LIMIT %d",
            $limit
        ), ARRAY_A);
        return $this->shape_rows($rows);
    }

    
    public function get_newest_brand($limit = 10) {
        if (!self::table_exists()) { return array(); }
        $limit = max(1, (int) $limit);
        global $wpdb;
        $table = self::table();
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$table}
              WHERE product_count > 0 AND brand_created_at IS NOT NULL
              ORDER BY brand_created_at DESC, product_count DESC
              LIMIT %d",
            $limit
        ), ARRAY_A);
        return $this->shape_rows($rows);
    }

    
    public function get_newest_product($limit = 10) {
        if (!self::table_exists()) { return array(); }
        $limit = max(1, (int) $limit);
        global $wpdb;
        $table = self::table();
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$table}
              WHERE product_count > 0 AND newest_product_at IS NOT NULL
              ORDER BY newest_product_at DESC
              LIMIT %d",
            $limit
        ), ARRAY_A);
        return $this->shape_rows($rows);
    }

    
    public function get_for_user($user_id, $limit = 5) {
        $user_id = (int) $user_id;
        $limit   = max(1, (int) $limit);
        if ($user_id <= 0 || !self::table_exists()) { return array(); }
        if (!class_exists('AIEO_Customer_Intelligence_Query')) { return array(); }

        $top_ids = AIEO_Customer_Intelligence_Query::get_top_brands($user_id, $limit);
        if (empty($top_ids)) { return array(); }
        return $this->get_by_ids($top_ids);
    }

    public function get_by_ids(array $brand_ids) {
        $ids = array_values(array_filter(array_map('intval', $brand_ids), function ($v) { return $v > 0; }));
        if (empty($ids)) { return array(); }
        if (!self::table_exists()) { return array(); }
        global $wpdb;
        $table = self::table();
        $placeholders = implode(',', array_fill(0, count($ids), '%d'));
        $sql = $wpdb->prepare(
            "SELECT * FROM {$table} WHERE brand_id IN ({$placeholders})",
            $ids
        );
        $rows = $wpdb->get_results($sql, ARRAY_A);
        
        $by_id = array();
        if (is_array($rows)) {
            foreach ($rows as $r) { $by_id[(int) $r['brand_id']] = $r; }
        }
        $out = array();
        foreach ($ids as $id) {
            if (isset($by_id[$id]) && (int) $by_id[$id]['product_count'] > 0) {
                $out[] = $this->shape_row($by_id[$id]);
            }
        }
        return $out;
    }

    public function get_by_id($brand_id) {
        $brand_id = (int) $brand_id;
        if ($brand_id <= 0 || !self::table_exists()) { return null; }
        global $wpdb;
        $table = self::table();
        $row = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$table} WHERE brand_id = %d",
            $brand_id
        ), ARRAY_A);
        return $row ? $this->shape_row($row) : null;
    }

    
    private function shape_row(array $r) {
        static $permalink_memo = array();
        $brand_id = (int) $r['brand_id'];
        if (!isset($permalink_memo[$brand_id])) {
            $link = get_term_link($brand_id, isset($r['taxonomy']) ? (string) $r['taxonomy'] : 'product_brand');
            $permalink_memo[$brand_id] = is_wp_error($link) ? '' : (string) $link;
        }
        return array(
            'term_id'         => $brand_id,
            'name'            => (string) $r['brand_name'],
            'slug'            => (string) $r['brand_slug'],
            'permalink'       => $permalink_memo[$brand_id],
            'letter'          => isset($r['letter']) ? (string) $r['letter'] : '#',
            'product_count'   => (int) $r['product_count'],
            'in_stock_count'  => (int) $r['in_stock_count'],
            'total_sales'     => (int) ($r['total_sales'] ?? 0),
            'hero_image_id'   => (int) $r['hero_image_id'],
            'logo_image_id'   => (int) $r['logo_image_id'],
            'hero_url'        => $r['hero_image_id'] ? (string) wp_get_attachment_image_url((int) $r['hero_image_id'], 'medium_large') : '',
            'logo_url'        => $r['logo_image_id'] ? (string) wp_get_attachment_image_url((int) $r['logo_image_id'], 'medium') : '',
            'rating_avg'      => isset($r['rating_avg']) && $r['rating_avg'] !== null ? (float) $r['rating_avg'] : null,
            'rating_count'    => (int) ($r['rating_count'] ?? 0),
            'promo'           => (int) ($r['promo'] ?? 0),
            'priority'        => (int) ($r['priority'] ?? 0),
            'brand_created_at'  => (string) ($r['brand_created_at']  ?? ''),
            'newest_product_at' => (string) ($r['newest_product_at'] ?? ''),
        );
    }

    private function shape_rows($rows) {
        $out = array();
        if (!is_array($rows)) { return $out; }
        foreach ($rows as $r) { $out[] = $this->shape_row($r); }
        return $out;
    }

    
    
    

    
    public function refresh($brand_ids = null) {
        global $wpdb;
        $started = microtime(true);
        if (!self::table_exists()) {
            return array('rows_written' => 0, 'duration' => 0.0, 'scope' => 'no_table');
        }

        $table       = self::table();
        $vitals      = $wpdb->prefix . 'aieo_core_product_vitals';
        $variations  = $wpdb->prefix . 'aieo_core_variation_vitals';
        $popularity  = $wpdb->prefix . 'aieo_core_category_brand_popularity';
        $brand_extra = $wpdb->prefix . 'aieo_dmm_brand_extras';
        $rating_stat = $wpdb->prefix . 'aieo_rating_stats';
        $taxonomy    = 'product_brand';

        $scope_clause = '';
        if (is_array($brand_ids) && count($brand_ids) > 0) {
            $ids = array_values(array_filter(array_map('intval', $brand_ids), function ($v) { return $v > 0; }));
            if (empty($ids)) {
                return array('rows_written' => 0, 'duration' => 0.0, 'scope' => 'noop');
            }
            $list = implode(',', $ids);
            $scope_clause = " AND v.brand_id IN ({$list})";
        }

        
        
        
        
        
        
        
        
        
        
        
        $stock_subq = "
            SELECT pv.product_id AS parent_id,
                   CASE WHEN pv.variation_count > 0
                        THEN COALESCE(SUM(CASE WHEN var.stock > 0 THEN 1 ELSE 0 END), 0)
                        ELSE CASE WHEN (pv.stock > 0 OR pv.stock_status = 'instock') THEN 1 ELSE 0 END END AS in_stock
              FROM {$vitals} pv
         LEFT JOIN {$variations} var ON var.parent_id = pv.product_id
             WHERE pv.parent_id = pv.product_id
               AND pv.brand_id IS NOT NULL AND pv.brand_id > 0
             GROUP BY pv.product_id, pv.variation_count, pv.stock, pv.stock_status
        ";

        $sql = "
            INSERT INTO {$table}
                (brand_id, brand_name, brand_slug, taxonomy, letter,
                 product_count, in_stock_count, total_sales, total_turnover,
                 brand_created_at, newest_product_at,
                 hero_image_id, logo_image_id, rating_avg, rating_count,
                 promo, priority, last_computed)
            SELECT
                v.brand_id AS brand_id,
                COALESCE(MAX(v.brand), '')      AS brand_name,
                COALESCE(MAX(v.brand_slug), '') AS brand_slug,
                '{$taxonomy}' AS taxonomy,
                CASE
                    WHEN MAX(v.brand) REGEXP '^[A-Za-z]'
                        THEN UPPER(LEFT(MAX(v.brand), 1))
                    ELSE '#'
                END AS letter,
                COUNT(DISTINCT v.product_id) AS product_count,
                COALESCE(SUM(stk.in_stock), 0) AS in_stock_count,
                COALESCE(MAX(pop.total_sales), 0)            AS total_sales,
                COALESCE(MAX(pop.total_turnover), 0.00)      AS total_turnover,
                MIN(v.product_creation_date) AS brand_created_at,
                MAX(v.product_creation_date) AS newest_product_at,
                COALESCE(MAX(be.hero_image_id), 0) AS hero_image_id,
                COALESCE(MAX(be.logo_image_id), 0) AS logo_image_id,
                CASE WHEN MAX(rs.count_total) > 0
                     THEN ROUND(MAX(rs.sum_total) / MAX(rs.count_total), 2)
                     ELSE NULL END AS rating_avg,
                COALESCE(MAX(rs.count_total), 0) AS rating_count,
                COALESCE(MAX(be.promo), 0)    AS promo,
                COALESCE(MAX(be.priority), 0) AS priority,
                NOW() AS last_computed
              FROM {$vitals} v
         LEFT JOIN ({$stock_subq}) stk ON stk.parent_id = v.product_id
         LEFT JOIN {$popularity} pop
                ON pop.brand_id = v.brand_id AND pop.category_id IS NULL
         LEFT JOIN {$brand_extra} be
                ON be.term_id = v.brand_id AND be.taxonomy = '{$taxonomy}'
         LEFT JOIN {$rating_stat} rs
                ON rs.product_id = v.brand_id AND rs.object_type = 'brand'
             WHERE v.parent_id = v.product_id
               AND v.brand_id IS NOT NULL AND v.brand_id > 0
               {$scope_clause}
             GROUP BY v.brand_id
            ON DUPLICATE KEY UPDATE
                brand_name        = VALUES(brand_name),
                brand_slug        = VALUES(brand_slug),
                taxonomy          = VALUES(taxonomy),
                letter            = VALUES(letter),
                product_count     = VALUES(product_count),
                in_stock_count    = VALUES(in_stock_count),
                total_sales       = VALUES(total_sales),
                total_turnover    = VALUES(total_turnover),
                brand_created_at  = VALUES(brand_created_at),
                newest_product_at = VALUES(newest_product_at),
                hero_image_id     = VALUES(hero_image_id),
                logo_image_id     = VALUES(logo_image_id),
                rating_avg        = VALUES(rating_avg),
                rating_count      = VALUES(rating_count),
                promo             = VALUES(promo),
                priority          = VALUES(priority),
                last_computed     = VALUES(last_computed)
        ";

        $rows = (int) $wpdb->query($sql);

        
        
        
        
        
        if ($scope_clause === '') {
            $wpdb->query(
                "DELETE bv FROM {$table} bv
              LEFT JOIN (SELECT DISTINCT brand_id FROM {$vitals}
                          WHERE parent_id = product_id
                            AND brand_id IS NOT NULL AND brand_id > 0) live
                     ON live.brand_id = bv.brand_id
                  WHERE live.brand_id IS NULL"
            );
        }

        $this->bump_version();

        $duration = round(microtime(true) - $started, 2);
        if (function_exists('aieo_debug_log')) {
            aieo_debug_log('AIEO_Core_Brand_Vitals::refresh ' . wp_json_encode(array(
                'scope' => $scope_clause === '' ? 'full' : 'incremental',
                'rows'  => $rows,
                'duration' => $duration,
            )));
        }

        return array(
            'rows_written' => $rows,
            'duration'     => $duration,
            'scope'        => $scope_clause === '' ? 'full' : 'incremental',
        );
    }

    
    public function drain_dirty() {
        $ids = $this->get_dirty();
        if (empty($ids)) { return 0; }
        $this->refresh($ids);
        delete_option(self::DIRTY_QUEUE_OPT);
        return count($ids);
    }

    public function mark_dirty(array $brand_ids) {
        $existing = $this->get_dirty();
        $merged = array_unique(array_merge($existing, array_map('intval', $brand_ids)));
        $merged = array_values(array_filter($merged, function ($v) { return $v > 0; }));
        if (empty($merged)) {
            delete_option(self::DIRTY_QUEUE_OPT);
            return;
        }
        update_option(self::DIRTY_QUEUE_OPT, $merged, false);
    }

    public function get_dirty() {
        $raw = get_option(self::DIRTY_QUEUE_OPT, array());
        return is_array($raw) ? array_values(array_filter(array_map('intval', $raw), function ($v) { return $v > 0; })) : array();
    }

    
    
    
    

    public function cache_version() {
        $v = wp_cache_get(self::CACHE_KEY_VER, self::CACHE_GROUP);
        if ($v === false) {
            $v = (int) get_option('aieo_brand_vitals_cache_version', 1);
            wp_cache_set(self::CACHE_KEY_VER, $v, self::CACHE_GROUP, 0);
        }
        return (int) $v;
    }

    public function bump_version() {
        $v = $this->cache_version() + 1;
        update_option('aieo_brand_vitals_cache_version', $v, false);
        wp_cache_set(self::CACHE_KEY_VER, $v, self::CACHE_GROUP, 0);
    }

    
    
    

    public function on_product_save($product_id) {
        $product_id = (int) $product_id;
        if ($product_id <= 0) { return; }
        
        
        
        $terms = wp_get_post_terms($product_id, 'product_brand', array('fields' => 'ids'));
        if (is_wp_error($terms) || empty($terms)) { return; }
        $this->mark_dirty(array_map('intval', $terms));
    }

    public function on_brand_term_change($term_id) {
        $term_id = (int) $term_id;
        if ($term_id <= 0) { return; }
        $this->mark_dirty(array($term_id));
    }

    
    
    
    

    public function ajax_brand_slider_bundle() {
        check_ajax_referer('aieo_brand_slider', 'nonce');
        $mode  = isset($_POST['mode'])  ? sanitize_key((string) wp_unslash($_POST['mode'])) : 'top';
        $limit = isset($_POST['limit']) ? max(1, min(50, (int) wp_unslash($_POST['limit']))) : 10;

        switch ($mode) {
            case 'new_brand':   $brands = $this->get_newest_brand($limit); break;
            case 'new_product': $brands = $this->get_newest_product($limit); break;
            case 'favourites':  $brands = $this->get_for_user(get_current_user_id(), $limit); break;
            case 'manual':
                $raw = isset($_POST['brand_ids']) ? (array) wp_unslash($_POST['brand_ids']) : array();
                $brands = $this->get_by_ids(array_map('intval', $raw));
                if (count($brands) > $limit) { $brands = array_slice($brands, 0, $limit); }
                break;
            case 'top':
            default:
                $brands = $this->get_top($limit);
        }
        wp_send_json_success(array('mode' => $mode, 'brands' => $brands));
    }
}

if (defined('WP_CLI') && WP_CLI && !class_exists('AIEO_CLI_Brand_Vitals')) {

    class AIEO_CLI_Brand_Vitals {

        
        public function refresh($args, $assoc_args) {
            $bv = AIEO_Core_Brand_Vitals::instance();
            if (!empty($assoc_args['drain-dirty'])) {
                $n = $bv->drain_dirty();
                \WP_CLI::success(sprintf('Drained dirty queue: %d brands.', $n));
                return;
            }
            $brand_ids = null;
            if (!empty($assoc_args['brand_ids'])) {
                $brand_ids = array_map('intval', explode(',', (string) $assoc_args['brand_ids']));
            }
            $result = $bv->refresh($brand_ids);
            \WP_CLI::success(sprintf(
                '%s refresh: %d rows, %.2fs',
                $result['scope'],
                $result['rows_written'],
                $result['duration']
            ));
        }

        
        public function dirty($args, $assoc_args) {
            $bv = AIEO_Core_Brand_Vitals::instance();
            $ids = $bv->get_dirty();
            \WP_CLI::log('Dirty queue depth: ' . count($ids));
            if (!empty($ids)) {
                \WP_CLI::log('Brand IDs: ' . implode(',', $ids));
            }
        }
    }

    \WP_CLI::add_command('aieo brand-vitals', 'AIEO_CLI_Brand_Vitals');
}
