<?php

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

class AIEO_Effective_Prices {

    const TABLE_NAME       = 'aieo_effective_prices';
    const SCHEMA_OPTION    = 'aieo_effective_prices_schema_version';
    const SCHEMA_VERSION   = 2;

    
    private static $hooks_registered = false;

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

        
        if (self::is_enabled()) {
            add_filter('woocommerce_get_price_html', array(__CLASS__, 'maybe_filter_price_html'), 50, 2);
            add_filter('woocommerce_product_get_price', array(__CLASS__, 'maybe_filter_get_price'), 90, 2);
        }

        
        
        
        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_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') {
            global $wpdb;
            if (self::table_exists()) {
                $wpdb->delete(self::table_name(), array('product_id' => (int) $post->ID), array('%d'));
            }
        } elseif ($new_status === 'publish' && $old_status !== 'publish' && class_exists('AIEO_Recompute_Queue')) {
            AIEO_Recompute_Queue::enqueue(AIEO_Recompute_Queue::SURFACE_PRICES, (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;
        $wpdb->delete(self::table_name(), array('product_id' => $post_id), array('%d'));
    }

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

    
    public static function get_for($product_id, $audience_key) {
        global $wpdb;
        $product_id = (int) $product_id;
        if ($product_id <= 0 || !is_string($audience_key) || $audience_key === '') {
            return null;
        }
        
        
        
        static $l1 = array();
        $key = $audience_key . ':' . $product_id;
        if (array_key_exists($key, $l1)) { return $l1[$key]; }

        $table = self::table_name();
        if (!self::table_exists()) { return $l1[$key] = null; }

        
        $row = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$table} WHERE product_id = %d AND audience_key = %s LIMIT 1",
            $product_id,
            $audience_key
        ), ARRAY_A);

        return $l1[$key] = (is_array($row) ? self::hydrate($row) : null);
    }

    
    public static function get_for_batch(array $product_ids, $audience_key) {
        global $wpdb;
        $ids = array_unique(array_filter(array_map('intval', $product_ids)));
        if (empty($ids) || !is_string($audience_key) || $audience_key === '') {
            return array();
        }
        $table = self::table_name();
        if (!self::table_exists()) { return array(); }

        $placeholders = implode(',', array_fill(0, count($ids), '%d'));
        $args = array_merge(array_values($ids), array($audience_key));
        
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$table} WHERE product_id IN ({$placeholders}) AND audience_key = %s",
            $args
        ), ARRAY_A);

        $out = array();
        if (is_array($rows)) {
            foreach ($rows as $r) {
                $hydrated = self::hydrate($r);
                $out[(int) $hydrated['product_id']] = $hydrated;
            }
        }
        return $out;
    }

    
    public static function recompute($product_id, $audience_key) {
        $product_id = (int) $product_id;
        if ($product_id <= 0 || !is_string($audience_key) || $audience_key === '') {
            return null;
        }
        if (!class_exists('AIEO_DMM_Pricing_Engine') || !function_exists('wc_get_product')) {
            return null;
        }

        
        
        
        
        
        
        $post = get_post($product_id);
        if (!$post || $post->post_type !== 'product' || $post->post_status !== 'publish') {
            
            
            global $wpdb;
            $wpdb->delete(self::table_name(), array('product_id' => $product_id), array('%d'));
            return null;
        }

        $product = wc_get_product($product_id);
        if (!$product) { return null; }

        $base = (float) $product->get_regular_price();
        if ($base <= 0) {
            $base = (float) $product->get_price();
        }
        if ($base <= 0) {
            
            return null;
        }

        $rep_user = self::representative_user_for_audience($audience_key);

        
        $original = get_current_user_id();
        if ($rep_user > 0 && $rep_user !== $original) {
            wp_set_current_user($rep_user);
        }

        try {
            $engine = AIEO_DMM_Pricing_Engine::instance();
            
            $sale_price = (float) $engine->get_effective_price($product_id, $rep_user, $base);
        } finally {
            if ($rep_user > 0 && $rep_user !== $original) {
                wp_set_current_user($original);
            }
        }

        
        
        
        
        
        
        
        $sale_undercut  = $sale_price > 0 && $sale_price < $base;
        $native_on_sale = method_exists($product, 'is_on_sale') ? (bool) $product->is_on_sale() : false;
        
        
        
        
        
        if (!$native_on_sale && method_exists($product, 'is_type') && $product->is_type('variable')) {
            foreach ((array) $product->get_children() as $vid) {
                $v = function_exists('wc_get_product') ? wc_get_product((int) $vid) : null;
                if ($v && method_exists($v, 'is_on_sale') && $v->is_on_sale()) {
                    $native_on_sale = true;
                    break;
                }
            }
        }
        $was_on_sale = $sale_undercut || $native_on_sale;

        $sale_discount_pct = null;
        $effective_sale    = $sale_undercut ? $sale_price : null;
        if ($sale_undercut) {
            $sale_discount_pct = round((1.0 - ($sale_price / $base)) * 100.0, 2);
        } elseif ($native_on_sale) {
            
            
            
            
            
            if ($product->is_type('variable') && method_exists($product, 'get_variation_regular_price')) {
                $reg_min  = (float) $product->get_variation_regular_price('min');
                $sale_min = (float) $product->get_variation_sale_price('min');
            } else {
                $reg_min  = (float) $product->get_regular_price();
                $sale_min = (float) $product->get_sale_price();
            }
            if ($reg_min > 0 && $sale_min > 0 && $sale_min < $reg_min) {
                $sale_discount_pct = round((1.0 - ($sale_min / $reg_min)) * 100.0, 2);
                $effective_sale    = $sale_min;
            }
        }

        
        
        
        
        
        
        global $wpdb;
        $rp_tbl = $wpdb->prefix . 'aieo_dmm_role_prices';
        $role_price_applied = (bool) $wpdb->get_var($wpdb->prepare(
            "SELECT 1 FROM {$rp_tbl} WHERE product_id = %d OR parent_id = %d LIMIT 1",
            $product_id,
            $product_id
        ));
        $monthly_offer_active = class_exists('AIEO_DMM_Brand_Discounts')
            ? (bool) AIEO_DMM_Brand_Discounts::is_monthly_offer_active($product_id)
            : false;

        
        
        $source_rule_type = null;
        if ($role_price_applied) {
            $source_rule_type = 'role';
        } elseif ($monthly_offer_active) {
            $source_rule_type = 'monthly_offer';
        } elseif ($native_on_sale) {
            $source_rule_type = 'native_sale';
        }

        $row = array(
            'product_id'           => $product_id,
            'audience_key'         => $audience_key,
            'base_price'           => $base,
            'sale_price'           => $effective_sale,
            'was_on_sale'          => $was_on_sale ? 1 : 0,
            'role_price_applied'   => $role_price_applied ? 1 : 0,
            'monthly_offer_active' => $monthly_offer_active ? 1 : 0,
            'sale_discount_pct'    => $sale_discount_pct,
            'source_rule_id'       => null,
            'source_rule_type'     => $source_rule_type,
            'valid_from'           => null,
            'valid_until'          => null,
            'computed_at'          => current_time('mysql', true),
        );

        
        
        global $wpdb;
        $table = self::table_name();
        $wpdb->replace($table, $row, array(
            '%d', 
            '%s', 
            '%f', 
            '%s', 
            '%d', 
            '%d', 
            '%d', 
            '%s', 
            '%s', 
            '%s', 
            '%s', 
            '%s', 
            '%s', 
        ));

        return self::hydrate($row);
    }

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

    
    
    

    
    public static function maybe_filter_price_html($price_html, $product) {
        if (!is_object($product) || !method_exists($product, 'get_id')) {
            return $price_html;
        }
        $row = self::get_for(
            (int) $product->get_id(),
            class_exists('AIEO_Identity_Bridge') ? AIEO_Identity_Bridge::audience_key_for_current_user() : 'guest'
        );
        if (!$row || self::is_stale($row)) {
            return $price_html;
        }

        
        
        $base = (float) $row['base_price'];
        $sale = isset($row['sale_price']) ? (float) $row['sale_price'] : null;

        if ($sale !== null && $sale > 0 && $sale < $base) {
            return wc_format_sale_price(wc_price($base), wc_price($sale));
        }
        return wc_price($base);
    }

    
    public static function maybe_filter_get_price($price, $product) {
        if (!is_object($product) || !method_exists($product, 'get_id')) {
            return $price;
        }
        $row = self::get_for(
            (int) $product->get_id(),
            class_exists('AIEO_Identity_Bridge') ? AIEO_Identity_Bridge::audience_key_for_current_user() : 'guest'
        );
        if (!$row || self::is_stale($row)) {
            return $price;
        }
        if (isset($row['sale_price']) && (float) $row['sale_price'] > 0) {
            return number_format((float) $row['sale_price'], wc_get_price_decimals(), '.', '');
        }
        return $price;
    }

    
    private static function is_stale(array $row) {
        $ttl = (int) get_option('aieo_effective_prices_ttl_seconds', 0);
        if ($ttl <= 0) { return false; }
        $computed = isset($row['computed_at']) ? strtotime($row['computed_at'] . ' UTC') : 0;
        if ($computed <= 0) { return true; }
        return (time() - $computed) > $ttl;
    }

    
    
    

    
    public static function representative_user_for_audience($audience_key) {
        if ($audience_key === 'guest' || $audience_key === '') {
            return 0;
        }
        if (strpos($audience_key, 'role:') === 0) {
            $role = substr($audience_key, 5);
            $users = get_users(array(
                'role'   => $role,
                'number' => 1,
                'fields' => 'ID',
                'orderby' => 'ID',
                'order'  => 'ASC',
            ));
            return !empty($users) ? (int) $users[0] : 0;
        }
        if (strpos($audience_key, 'tier:') === 0) {
            global $wpdb;
            $tier_id = (int) substr($audience_key, 5);
            $table = $wpdb->prefix . 'aieo_dmm_loyalty_assignments';
            $exists = (int) $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s",
                $table
            ));
            if (!$exists) { return 0; }
            
            $uid = $wpdb->get_var($wpdb->prepare(
                "SELECT user_id FROM {$table} WHERE class_id = %d ORDER BY user_id ASC LIMIT 1",
                $tier_id
            ));
            return (int) $uid;
        }
        return 0;
    }

    
    
    

    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} (
            product_id BIGINT(20) UNSIGNED NOT NULL,
            audience_key VARCHAR(64) NOT NULL,
            base_price DECIMAL(12,2) NOT NULL,
            sale_price DECIMAL(12,2) DEFAULT NULL,
            was_on_sale TINYINT(1) NOT NULL DEFAULT 0,
            role_price_applied TINYINT(1) NOT NULL DEFAULT 0,
            monthly_offer_active TINYINT(1) NOT NULL DEFAULT 0,
            sale_discount_pct DECIMAL(5,2) DEFAULT NULL,
            source_rule_id BIGINT(20) UNSIGNED DEFAULT NULL,
            source_rule_type VARCHAR(32) DEFAULT NULL,
            valid_from DATETIME DEFAULT NULL,
            valid_until DATETIME DEFAULT NULL,
            computed_at DATETIME NOT NULL,
            PRIMARY KEY (product_id, audience_key),
            KEY ix_audience (audience_key),
            KEY ix_source (source_rule_id, source_rule_type),
            KEY ix_valid (valid_until),
            KEY ix_was_on_sale (was_on_sale),
            KEY ix_role_price (role_price_applied),
            KEY ix_monthly (monthly_offer_active)
        ) {$charset};";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql);

        
        
        
        self::ensure_v2_columns();

        update_option(self::SCHEMA_OPTION, self::SCHEMA_VERSION, 'no');
    }

    
    private static function ensure_v2_columns() {
        global $wpdb;
        $table = self::table_name();
        
        $cols = $wpdb->get_col("SHOW COLUMNS FROM {$table}", 0);
        if (!is_array($cols)) { return; }
        $cols = array_flip($cols);

        $alters = array();
        if (!isset($cols['was_on_sale'])) {
            $alters[] = "ADD COLUMN was_on_sale TINYINT(1) NOT NULL DEFAULT 0 AFTER sale_price";
        }
        if (!isset($cols['role_price_applied'])) {
            $alters[] = "ADD COLUMN role_price_applied TINYINT(1) NOT NULL DEFAULT 0 AFTER was_on_sale";
        }
        if (!isset($cols['monthly_offer_active'])) {
            $alters[] = "ADD COLUMN monthly_offer_active TINYINT(1) NOT NULL DEFAULT 0 AFTER role_price_applied";
        }
        if (!isset($cols['sale_discount_pct'])) {
            $alters[] = "ADD COLUMN sale_discount_pct DECIMAL(5,2) DEFAULT NULL AFTER monthly_offer_active";
        }
        if (!empty($alters)) {
            
            $wpdb->query("ALTER TABLE {$table} " . implode(', ', $alters));
        }

        
        
        $existing_idx = $wpdb->get_col("SHOW INDEX FROM {$table}", 2); 
        $existing_idx = is_array($existing_idx) ? array_flip(array_unique($existing_idx)) : array();
        $idx_alters = array();
        if (!isset($existing_idx['ix_was_on_sale']))   { $idx_alters[] = "ADD KEY ix_was_on_sale (was_on_sale)"; }
        if (!isset($existing_idx['ix_role_price']))    { $idx_alters[] = "ADD KEY ix_role_price (role_price_applied)"; }
        if (!isset($existing_idx['ix_monthly']))       { $idx_alters[] = "ADD KEY ix_monthly (monthly_offer_active)"; }
        if (!empty($idx_alters)) {
            
            @$wpdb->query("ALTER TABLE {$table} " . implode(', ', $idx_alters));
        }
    }

    private static function hydrate(array $row) {
        $row['product_id']     = (int) ($row['product_id'] ?? 0);
        $row['audience_key']   = (string) ($row['audience_key'] ?? '');
        $row['base_price']     = (float) ($row['base_price'] ?? 0);
        $row['sale_price']     = isset($row['sale_price']) && $row['sale_price'] !== null && $row['sale_price'] !== ''
            ? (float) $row['sale_price'] : null;
        $row['source_rule_id'] = isset($row['source_rule_id']) ? (int) $row['source_rule_id'] : null;
        return $row;
    }
}
