<?php

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

class AIEO_Effective_Recos {

    const TABLE_NAME      = 'aieo_effective_recos';
    const SCHEMA_OPTION   = 'aieo_effective_recos_schema_version';
    const SCHEMA_VERSION  = 1;

    const SURFACE_RELATED       = 'related';
    const SURFACE_UPSELLS       = 'upsells';
    const SURFACE_CROSSSELLS    = 'crosssells';
    const SURFACE_COMPLEMENTARY = 'complementary';
    const SURFACE_SAME_NEEDS    = 'same_needs';
    const SURFACE_FBT           = 'fbt';

    const VALID_SURFACES = array(
        self::SURFACE_RELATED,
        self::SURFACE_UPSELLS,
        self::SURFACE_CROSSSELLS,
        self::SURFACE_COMPLEMENTARY,
        self::SURFACE_SAME_NEEDS,
        self::SURFACE_FBT,
    );

    
    private static $hooks_registered = false;

    public static function bootstrap() {
        self::maybe_install();
        if (self::$hooks_registered) { return; }
        self::$hooks_registered = true;

        
        
        
        
        
        add_action('woocommerce_product_set_stock_status', array(__CLASS__, 'on_stock_status_change'), 20, 3);
        add_action('woocommerce_variation_set_stock_status', array(__CLASS__, 'on_stock_status_change'), 20, 3);
        add_action('transition_post_status', array(__CLASS__, 'on_post_status_change'), 20, 3);
        add_action('before_delete_post', array(__CLASS__, 'on_before_delete'), 20, 1);
    }

    
    public static function on_stock_status_change($product_id, $new_status = '', $product = null) {
        $product_id = (int) $product_id;
        if ($product_id <= 0) { return; }

        
        
        $parent_id = (int) wp_get_post_parent_id($product_id);
        $effective_id = $parent_id > 0 ? $parent_id : $product_id;

        self::invalidate_target($effective_id);
        if (class_exists('AIEO_Recompute_Queue')) {
            AIEO_Recompute_Queue::enqueue(AIEO_Recompute_Queue::SURFACE_RECOS, $effective_id, '');
        }
    }

    
    public static function on_post_status_change($new_status, $old_status, $post) {
        if (!is_object($post) || !isset($post->post_type) || $post->post_type !== 'product') { return; }
        if ($new_status === $old_status) { return; }
        if ($old_status === 'publish' && $new_status !== 'publish') {
            self::invalidate_target((int) $post->ID);
        } elseif ($new_status === 'publish' && $old_status !== 'publish') {
            
            
            if (class_exists('AIEO_Recompute_Queue')) {
                AIEO_Recompute_Queue::enqueue(AIEO_Recompute_Queue::SURFACE_RECOS, (int) $post->ID, '');
            }
        }
    }

    
    public static function on_before_delete($post_id) {
        $post_id = (int) $post_id;
        if ($post_id <= 0 || !self::table_exists()) { return; }
        $post = get_post($post_id);
        if (!$post || $post->post_type !== 'product') { return; }

        global $wpdb;
        $table = self::table_name();
        
        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table} WHERE source_product_id = %d OR target_product_id = %d",
            $post_id, $post_id
        ));
    }

    public static function is_enabled() {
        return (bool) get_option('aieo_use_effective_recos', 0);
    }

    
    public static function get_top($source_product_id, $surface, $audience_key, $limit = 10) {
        global $wpdb;
        $source_product_id = (int) $source_product_id;
        $limit = max(1, (int) $limit);
        if ($source_product_id <= 0 || !in_array($surface, self::VALID_SURFACES, true)) {
            return array();
        }
        if (!self::table_exists()) { return array(); }

        $table = self::table_name();
        
        
        
        
        
        
        
        
        $rows = $wpdb->get_col($wpdb->prepare(
            "SELECT target_product_id FROM {$table}
             WHERE source_product_id = %d AND surface = %s AND audience_key = %s
             ORDER BY rank ASC
             LIMIT %d",
            $source_product_id,
            $surface,
            $audience_key,
            $limit
        ));
        if (empty($rows) && $audience_key !== 'guest') {
            
            $rows = $wpdb->get_col($wpdb->prepare(
                "SELECT target_product_id FROM {$table}
                 WHERE source_product_id = %d AND surface = %s AND audience_key = 'guest'
                 ORDER BY rank ASC
                 LIMIT %d",
                $source_product_id,
                $surface,
                $limit
            ));
        }
        return is_array($rows) ? array_map('intval', $rows) : array();
    }

    
    public static function get_top_full($source_product_id, $surface, $audience_key, $limit = 10) {
        global $wpdb;
        $source_product_id = (int) $source_product_id;
        $limit = max(1, (int) $limit);
        if ($source_product_id <= 0 || !in_array($surface, self::VALID_SURFACES, true)) {
            return array();
        }
        if (!self::table_exists()) { return array(); }

        $table = self::table_name();
        
        return (array) $wpdb->get_results($wpdb->prepare(
            "SELECT target_product_id, score, reason_code FROM {$table}
             WHERE source_product_id = %d AND surface = %s AND audience_key = %s
             ORDER BY rank ASC
             LIMIT %d",
            $source_product_id,
            $surface,
            $audience_key,
            $limit
        ), ARRAY_A);
    }

    
    public static function recompute($source_product_id, $audience_key) {
        global $wpdb;
        $source_product_id = (int) $source_product_id;
        if ($source_product_id <= 0 || !is_string($audience_key) || $audience_key === '') {
            return 0;
        }
        if (!function_exists('wc_get_product')) { return 0; }

        $product = wc_get_product($source_product_id);
        if (!$product) { return 0; }
        if (!self::table_exists()) { return 0; }

        
        
        
        if (!self::is_eligible_target($source_product_id)) {
            $table = self::table_name();
            
            $wpdb->query($wpdb->prepare(
                "DELETE FROM {$table} WHERE source_product_id = %d AND audience_key = %s",
                $source_product_id,
                $audience_key
            ));
            return 0;
        }

        $table = self::table_name();
        $written = 0;

        
        
        
        
        $sources = array(
            self::SURFACE_UPSELLS    => $product->get_upsell_ids(),
            self::SURFACE_CROSSSELLS => $product->get_cross_sell_ids(),
            self::SURFACE_RELATED    => self::related_ids_for($source_product_id),
        );

        
        
        if (class_exists('AIEO_DMM_Reco_Penalty') && method_exists('AIEO_DMM_Reco_Penalty', 'rerank')) {
            foreach ($sources as $surface => $ids) {
                if (!empty($ids)) {
                    $sources[$surface] = (array) AIEO_DMM_Reco_Penalty::rerank($ids);
                }
            }
        }

        
        
        
        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table} WHERE source_product_id = %d AND audience_key = %s",
            $source_product_id,
            $audience_key
        ));

        $now = current_time('mysql', true);
        foreach ($sources as $surface => $ids) {
            $rank = 1;
            foreach ((array) $ids as $tid) {
                $tid = (int) $tid;
                if ($tid <= 0 || $tid === $source_product_id) { continue; }
                if (!self::is_eligible_target($tid)) { continue; }
                if ($rank > 30) { break; } 

                $wpdb->insert(
                    $table,
                    array(
                        'source_product_id' => $source_product_id,
                        'surface'           => $surface,
                        'audience_key'      => $audience_key,
                        'rank'              => $rank,
                        'target_product_id' => $tid,
                        'score'             => 0,
                        'reason_code'       => null,
                        'computed_at'       => $now,
                    ),
                    array('%d', '%s', '%s', '%d', '%d', '%f', '%s', '%s')
                );
                $rank++;
                $written++;
            }
        }

        return $written;
    }

    
    private static function is_eligible_target($product_id) {
        static $memo = array();
        $product_id = (int) $product_id;
        if (isset($memo[$product_id])) { return $memo[$product_id]; }

        $post = get_post($product_id);
        if (!$post || $post->post_type !== 'product' || $post->post_status !== 'publish') {
            return $memo[$product_id] = false;
        }
        if (!function_exists('wc_get_product')) { return $memo[$product_id] = true; }
        $product = wc_get_product($product_id);
        if (!$product) { return $memo[$product_id] = false; }
        if (!$product->is_in_stock()) { return $memo[$product_id] = false; }

        return $memo[$product_id] = true;
    }

    
    public static function invalidate_target($target_product_id) {
        global $wpdb;
        $target_product_id = (int) $target_product_id;
        if ($target_product_id <= 0 || !self::table_exists()) { return 0; }
        $table = self::table_name();
        
        return (int) $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table} WHERE target_product_id = %d",
            $target_product_id
        ));
    }

    
    public static function recompute_all_audiences($source_product_id) {
        $total = 0;
        $audiences = class_exists('AIEO_Identity_Bridge')
            ? AIEO_Identity_Bridge::known_audience_keys()
            : array('guest');
        foreach ($audiences as $key) {
            $total += self::recompute($source_product_id, $key);
        }
        return $total;
    }

    
    private static function related_ids_for($product_id) {
        if (!function_exists('wc_get_related_products')) { return array(); }
        return (array) wc_get_related_products($product_id, 30);
    }

    
    
    

    public static function table_name() {
        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_name()
        ));
        return $cached = ($found > 0);
    }

    public static function maybe_install() {
        $current = (int) get_option(self::SCHEMA_OPTION, 0);
        if ($current >= self::SCHEMA_VERSION) {
            
            
            
            
            
            
            if (!is_admin() && !wp_doing_cron()) {
                return;
            }
            if (self::table_exists()) {
                return;
            }
        }
        global $wpdb;
        $table = self::table_name();
        $charset = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE {$table} (
            source_product_id BIGINT(20) UNSIGNED NOT NULL,
            surface VARCHAR(20) NOT NULL,
            audience_key VARCHAR(64) NOT NULL,
            rank TINYINT(3) UNSIGNED NOT NULL,
            target_product_id BIGINT(20) UNSIGNED NOT NULL,
            score DECIMAL(8,4) NOT NULL DEFAULT 0,
            reason_code VARCHAR(32) DEFAULT NULL,
            computed_at DATETIME NOT NULL,
            PRIMARY KEY (source_product_id, surface, audience_key, rank),
            KEY ix_target (target_product_id),
            KEY ix_audience_surface (audience_key, surface)
        ) {$charset};";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql);
        update_option(self::SCHEMA_OPTION, self::SCHEMA_VERSION, 'no');
    }
}
