<?php
if ( ! defined( 'ABSPATH' ) ) { exit; }

/**
 * KNSDD_Performance_Optimizer Class
 * 
 * N. ürün kampanyası ve diğer kampanyaların performansını optimize eder.
 */
class KNSDD_Performance_Optimizer {
    
    /** @var array Request-level cache */
    private static $request_cache = [];
    
    /** @var array Batch processing cache */
    private static $batch_cache = [];
    
    /**
     * Sepetteki tüm ürünler için kuralları tek seferde çeker ve cache'ler.
     */
    public static function batch_load_cart_rules() {
        if ( ! WC()->cart || WC()->cart->is_empty() ) {
            return [];
        }
        
        $cache_key = 'batch_cart_rules_' . WC()->cart->get_cart_hash();
        if ( isset( self::$request_cache[ $cache_key ] ) ) {
            return self::$request_cache[ $cache_key ];
        }
        
        $product_ids = [];
        $cart_items = [];
        
        foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
            $product_id = $cart_item['product_id'];
            $quantity = $cart_item['quantity'];
            
            $product_ids[] = $product_id;
            $cart_items[ $cart_item_key ] = [
                'product_id' => $product_id,
                'quantity' => $quantity,
                'item' => $cart_item
            ];
        }
        
        // Tüm ürünler için kuralları tek batch'te yükle
        $rules_map = self::batch_get_rules_for_products( array_unique( $product_ids ) );
        
        $result = [];
        foreach ( $cart_items as $cart_item_key => $data ) {
            $product_id = $data['product_id'];
            $quantity = $data['quantity'];
            
            $best_rule = null;
            if ( isset( $rules_map[ $product_id ] ) ) {
                $best_rule = self::find_best_rule_for_quantity( $rules_map[ $product_id ], $quantity );
            }
            
            $result[ $cart_item_key ] = [
                'rule' => $best_rule,
                'product_id' => $product_id,
                'quantity' => $quantity,
                'item' => $data['item']
            ];
        }
        
        self::$request_cache[ $cache_key ] = $result;
        return $result;
    }
    
    /**
     * Birden fazla ürün için kuralları toplu olarak getirir.
     */
    private static function batch_get_rules_for_products( array $product_ids ) {
        if ( empty( $product_ids ) ) {
            return [];
        }
        
        $cache_key = 'batch_rules_' . md5( implode( ',', $product_ids ) );
        if ( isset( self::$batch_cache[ $cache_key ] ) ) {
            return self::$batch_cache[ $cache_key ];
        }
        
        $all_groups = KNSDD_Data::get_groups();
        $all_group_dates = KNSDD_Data::get_all_group_dates();
        $current_user_id = self::get_current_user_id();
        $current_user_email = self::get_current_user_email();
        
        // Ürün kategorilerini toplu çek
        $product_categories = [];
        foreach ( $product_ids as $pid ) {
            $product_categories[ $pid ] = wc_get_product_term_ids( $pid, 'product_cat' );
        }
        
        $rules_map = [];
        
        // Her grup için kuralları kontrol et
        foreach ( $all_groups as $group ) {
            if ( KNSDD_Data::is_group_paused( $group ) ) { continue; }
            
            $dates = $all_group_dates[ $group ] ?? null;
            if ( ! $dates || 'open' !== KNSDD_Utils::get_group_status_info( $dates )['status'] ) {
                continue;
            }
            
            $rules = KNSDD_Data::get_rules_for_group( $group );
            
            foreach ( $rules as $rule ) {
                if ( empty( $rule['rule_id'] ) ) { continue; }
                
                $rule['group'] = $group;
                
                // Bu kural hangi ürünlere uygulanabilir?
                $applicable_products = self::get_applicable_products_for_rule( $rule, $product_ids, $product_categories );
                
                foreach ( $applicable_products as $pid ) {
                    if ( ! isset( $rules_map[ $pid ] ) ) {
                        $rules_map[ $pid ] = [];
                    }
                    $rules_map[ $pid ][] = $rule;
                }
            }
        }
        
        self::$batch_cache[ $cache_key ] = $rules_map;
        return $rules_map;
    }
    
    /**
     * Bir kural için geçerli ürün ID'lerini bulur.
     */
    private static function get_applicable_products_for_rule( $rule, $product_ids, $product_categories ) {
        $applicable = [];
        
        $rule_products = ! empty( $rule['product'] ) && is_array( $rule['product'] ) ? $rule['product'] : [];
        $rule_cats = isset( $rule['category'] ) ? (array) $rule['category'] : [];
        
        foreach ( $product_ids as $pid ) {
            $applies = false;
            // Varyasyonlar için ebeveyn kategorilerini devral (ürün kategorileri boşsa)
            $cats_for_match = $product_categories[ $pid ] ?? [];
            if ( empty( $cats_for_match ) ) {
                $par = (int) wp_get_post_parent_id( $pid );
                if ( $par > 0 ) {
                    $cats_for_match = wc_get_product_term_ids( $par, 'product_cat' );
                }
            }

            // Çift yönlü hiyerarşik kategori desteği
            $has_category_match = false;
            if ( ! empty( $rule_cats ) && ! empty( $cats_for_match ) ) {
                // 1. Ürün kategorilerini genişlet (alt → üst)
                $expanded_product_cats = array_map( 'intval', $cats_for_match );
                foreach ( $cats_for_match as $cat_id ) {
                    $ancestors = get_ancestors( (int) $cat_id, 'product_cat', 'taxonomy' );
                    if ( ! empty( $ancestors ) ) {
                        $expanded_product_cats = array_merge( $expanded_product_cats, array_map( 'intval', $ancestors ) );
                    }
                }
                $expanded_product_cats = array_unique( $expanded_product_cats );
                
                // 2. Kural kategorileri ile eşleşme
                $rule_cats_int = array_map( 'intval', $rule_cats );
                $has_category_match = ! empty( array_intersect( $expanded_product_cats, $rule_cats_int ) );
            }

            // AND semantiği: Hem product hem category set ise ikisi birden sağlanmalı
            if ( ! empty( $rule_products ) && ! empty( $rule_cats ) ) {
                if ( in_array( $pid, $rule_products, true ) && $has_category_match ) {
                    $applies = true;
                }
            } elseif ( ! empty( $rule_products ) ) {
                if ( in_array( $pid, $rule_products, true ) ) {
                    $applies = true;
                }
            } elseif ( ! empty( $rule_cats ) ) {
                if ( $has_category_match ) {
                    $applies = true;
                }
            }
            
            if ( $applies ) {
                $applicable[] = $pid;
            }
        }
        
        return $applicable;
    }
    
    /**
     * Verilen kurallar arasından miktar için en uygun olanı seçer.
     */
    private static function find_best_rule_for_quantity( $rules, $quantity ) {
        if ( empty( $rules ) ) {
            return null;
        }
        
        $current_user_id = self::get_current_user_id();
        $current_user_email = self::get_current_user_email();
        
        // Kullanım verilerini toplu çek
        $rule_ids = wp_list_pluck( $rules, 'rule_id' );
        $usage_map = KNSDD_Data::get_usage_for_multiple_rules( $rule_ids );
        $email_usage_map = [];
        if ( ! empty( $current_user_email ) ) {
            $email_usage_map = KNSDD_Data::get_usage_for_multiple_rules_by_email( $rule_ids, $current_user_email );
        }
        
        $applicable_rules = [];
        
        foreach ( $rules as $rule ) {
            // Miktar kontrolü (özel kampanyalar hariç)
            if ( ! isset( $rule['rule_type'] ) || 'special_campaign' !== $rule['rule_type'] ) {
                $min = (int) ( $rule['min'] ?? 1 );
                $max = (int) ( $rule['max'] ?? 0 );
                if ( $quantity < $min || ( $max > 0 && $quantity > $max ) ) {
                    continue;
                }
            }
            
            // Koşul kontrolü
            if ( self::is_rule_conditions_met_cached( $rule, $current_user_id, $usage_map, $current_user_email, $email_usage_map ) ) {
                $applicable_rules[] = $rule;
            }
        }
        
        if ( empty( $applicable_rules ) ) {
            return null;
        }
        
        // En iyiyi seç
        if ( count( $applicable_rules ) > 1 ) {
            usort( $applicable_rules, function( $a, $b ) {
                $prio_a = isset( $a['priority'] ) ? (int) $a['priority'] : 10;
                $prio_b = isset( $b['priority'] ) ? (int) $b['priority'] : 10;
                if ( $prio_a !== $prio_b ) {
                    return ( $prio_a < $prio_b ) ? 1 : -1;
                }
                $val_a = isset( $a['discount_value'] ) ? (float) $a['discount_value'] : 0.0;
                $val_b = isset( $b['discount_value'] ) ? (float) $b['discount_value'] : 0.0;
                return ( $val_a < $val_b ) ? 1 : -1;
            } );
        }
        
        return $applicable_rules[0];
    }
    
    /**
     * Kural koşullarını cache'lenmiş verilerle kontrol eder.
     */
    private static function is_rule_conditions_met_cached( $rule, $current_user_id, $usage_map, $current_user_email, $email_usage_map ) {
        if ( empty( $rule['rule_id'] ) ) return false;
        
        // Kullanıcı kontrolü
        if ( ! empty( $rule['allowed_customers'] ) && is_array( $rule['allowed_customers'] ) ) {
            if ( ! $current_user_id || ! in_array( $current_user_id, $rule['allowed_customers'] ) ) {
                return false;
            }
        } elseif ( ! empty( $rule['login_required'] ) && ! $current_user_id ) {
            return false;
        }
        
        // İlk sipariş kontrolü (first_order_only): user_id ve e-posta bazlı yedek kontrol
        $first_order_only = false;
        if ( isset( $rule['first_order_only'] ) ) {
            $first_order_only = (bool) $rule['first_order_only'];
        } elseif ( isset( $rule['ext'] ) && is_array( $rule['ext'] ) && isset( $rule['ext']['first_order_only'] ) ) {
            $first_order_only = (bool) $rule['ext']['first_order_only'];
        }
        if ( $first_order_only ) {
            static $order_count_cache = [];
            static $email_has_orders = []; // PHP 8+ için tek tanım
            
            if ( $current_user_id > 0 ) {
                if ( ! array_key_exists( $current_user_id, $order_count_cache ) ) {
                    if ( function_exists( 'wc_get_customer_order_count' ) ) {
                        $order_count_cache[ $current_user_id ] = (int) wc_get_customer_order_count( $current_user_id );
                    } else {
                        $order_count_cache[ $current_user_id ] = 0;
                    }
                }
                if ( $order_count_cache[ $current_user_id ] > 0 ) {
                    return false; // İlk sipariş değil
                }
                // Email fallback: user_id sipariş sayısı 0 ve e-posta varsa, email ile en az 1 sipariş var mı?
                if ( $order_count_cache[ $current_user_id ] === 0 && ! empty( $current_user_email ) && function_exists( 'wc_get_orders' ) ) {
                    $eml = strtolower( sanitize_email( $current_user_email ) );
                    if ( ! array_key_exists( $eml, $email_has_orders ) ) {
                        $valid_statuses = apply_filters( 'knsdd_first_order_valid_statuses', array( 'processing', 'completed', 'on-hold' ) );
                        $ids = wc_get_orders( array(
                            'limit'         => 1,
                            'return'        => 'ids',
                            'status'        => $valid_statuses,
                            'billing_email' => $eml,
                        ) );
                        $email_has_orders[ $eml ] = ! empty( $ids );
                    }
                    if ( $email_has_orders[ $eml ] ) {
                        return false; // E-posta ile geçmiş sipariş bulundu -> ilk sipariş indirimi uygulanmaz
                    }
                }
            } else {
                // Misafir: e-posta yoksa ilk sipariş doğrulanamaz
                if ( empty( $current_user_email ) ) { return false; }
                if ( function_exists( 'wc_get_orders' ) ) {
                    $eml = strtolower( sanitize_email( $current_user_email ) );
                    if ( ! array_key_exists( $eml, $email_has_orders ) ) {
                        $valid_statuses = apply_filters( 'knsdd_first_order_valid_statuses', array( 'processing', 'completed', 'on-hold' ) );
                        $ids = wc_get_orders( array(
                            'limit'         => 1,
                            'return'        => 'ids',
                            'status'        => $valid_statuses,
                            'billing_email' => $eml,
                        ) );
                        $email_has_orders[ $eml ] = ! empty( $ids );
                    }
                    if ( $email_has_orders[ $eml ] ) {
                        return false; // E-posta ile geçmiş sipariş bulundu -> ilk sipariş indirimi uygulanmaz
                    }
                } else {
                    return false; // API yoksa doğrulanamaz
                }
            }
        }
        
        // Kural bazlı çerez kontrolü kaldırıldı - sadece veritabanı kontrolü kullanılıyor
        
        // Grup çerez ve grup kilidi kontrolleri kaldırıldı.
        // Artık sadece per_customer_limit ile kural bazlı limit kontrolü yapılıyor.
        
        // Kullanım limiti kontrolü
        $rule_id = $rule['rule_id'];
        $usage = $usage_map[ $rule_id ] ?? [ 'total' => 0, 'members_only_total' => 0, 'users' => [] ];
        
        $total_limit = (int) ( $rule['total_limit'] ?? 0 );
        if ( $total_limit > 0 ) {
            $current_usage = ! empty( $rule['login_required'] ) ? $usage['members_only_total'] : $usage['total'];
            if ( $current_usage >= $total_limit ) {
                return false;
            }
        }
        
        $per_customer_limit = (int) ( $rule['per_customer_limit'] ?? 0 );
        if ( $per_customer_limit > 0 ) {
            $user_usage = ( $current_user_id > 0 ) ? (int) ( $usage['users'][ $current_user_id ] ?? 0 ) : 0;
            $email_count = ( ! empty( $current_user_email ) ) ? (int) ( $email_usage_map[ $rule_id ] ?? 0 ) : 0;
            if ( $user_usage >= $per_customer_limit || $email_count >= $per_customer_limit ) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Mevcut kullanıcı ID'sini alır.
     */
    private static function get_current_user_id() {
        $current_user_id = (int) get_current_user_id();
        if ( $current_user_id <= 0 && function_exists('WC') && WC()->customer ) {
            $wc_uid = (int) WC()->customer->get_id();
            if ( $wc_uid > 0 ) { $current_user_id = $wc_uid; }
        }
        return $current_user_id;
    }
    
    /**
     * Mevcut kullanıcı email'ini alır.
     */
    private static function get_current_user_email() {
        $current_user_email = '';
        if ( function_exists('WC') && WC()->customer ) {
            $current_user_email = sanitize_email( WC()->customer->get_email() );
            if ( empty( $current_user_email ) ) {
                $current_user_email = sanitize_email( WC()->customer->get_billing_email() );
            }
        }
        if ( empty( $current_user_email ) ) {
            $current_user_id = self::get_current_user_id();
            if ( $current_user_id > 0 ) {
                $u = get_user_by( 'id', $current_user_id );
                if ( $u && ! empty( $u->user_email ) ) { 
                    $current_user_email = sanitize_email( $u->user_email ); 
                }
            }
        }
        return $current_user_email;
    }
    
    /**
     * Request cache'ini temizler.
     */
    public static function clear_request_cache() {
        self::$request_cache = [];
        self::$batch_cache = [];
    }
    
    /**
     * Cache invalidation - Discount Engine ile senkronize
     */
    public static function invalidate_cache_for_rule( $rule_id ) {
        // Performance Optimizer cache'ini temizle
        self::clear_request_cache();
        
        // Discount Engine transient cache'ini de temizle
        $cache_version = get_option( 'knsdd_cache_version', 1 );
        update_option( 'knsdd_cache_version', $cache_version + 1 );
    }
    
    /**
     * Cache invalidation - Grup için
     */
    public static function invalidate_cache_for_group( $group ) {
        self::clear_request_cache();
        
        // Grup cache'ini temizle
        $cache_version = get_option( 'knsdd_cache_version', 1 );
        update_option( 'knsdd_cache_version', $cache_version + 1 );
    }
    
    /**
     * N. ürün kampanyası için optimize edilmiş validasyon.
     */
    public static function validate_nth_percent_off_optimized( $rule ) {
        $nth = isset( $rule['nth'] ) ? (int) $rule['nth'] : 0;
        if ( $nth <= 0 ) {
            return false;
        }
        
        // Batch cache'den sepet verilerini al
        $cart_data = self::batch_load_cart_rules();
        $total_eligible_quantity = 0;
        
        foreach ( $cart_data as $data ) {
            if ( $data['rule'] && $data['rule']['rule_id'] === $rule['rule_id'] ) {
                $total_eligible_quantity += $data['quantity'];
            }
        }
        
        return $total_eligible_quantity >= $nth;
    }
    
    /**
     * Toplu grup kullanım kontrolü - N+1 problemini çözer.
     */
    public static function batch_get_group_usage_for_customer( array $groups, $user_id, $email ) {
        if ( empty( $groups ) ) {
            return [];
        }
        
        $cache_key = 'batch_group_usage_' . md5( implode(',', $groups) . '|' . $user_id . '|' . $email );
        if ( isset( self::$request_cache[ $cache_key ] ) ) {
            return self::$request_cache[ $cache_key ];
        }
        
        // KNSDD_Data'daki mevcut fonksiyonu kullan ama cache'le
        $result = [];
        if ( class_exists('KNSDD_Data') && method_exists('KNSDD_Data', 'get_group_usage_for_customer') ) {
            $result = KNSDD_Data::get_group_usage_for_customer( $groups, $user_id, $email );
        }
        
        self::$request_cache[ $cache_key ] = $result;
        return $result;
    }
    
    /**
     * Kullanıcı kimlik bilgilerini optimize edilmiş şekilde alır.
     */
    public static function get_user_identity() {
        $cache_key = 'user_identity';
        if ( isset( self::$request_cache[ $cache_key ] ) ) {
            return self::$request_cache[ $cache_key ];
        }
        
        // Kimlik: Önce WP kullanıcı ID, yoksa WC customer ID, yoksa email
        $current_user_id = (int) get_current_user_id();
        if ( $current_user_id <= 0 && function_exists('WC') && WC()->customer ) {
            $wc_uid = (int) WC()->customer->get_id();
            if ( $wc_uid > 0 ) { $current_user_id = $wc_uid; }
        }
        
        $current_user_email = '';
        if ( function_exists('WC') && WC()->customer ) {
            $current_user_email = sanitize_email( WC()->customer->get_email() );
            if ( empty( $current_user_email ) ) {
                $current_user_email = sanitize_email( WC()->customer->get_billing_email() );
            }
        }
        if ( empty( $current_user_email ) && $current_user_id > 0 ) {
            $u = get_user_by( 'id', $current_user_id );
            if ( $u && ! empty( $u->user_email ) ) { 
                $current_user_email = sanitize_email( $u->user_email ); 
            }
        }
        
        $result = [
            'user_id' => $current_user_id,
            'email' => $current_user_email
        ];
        
        self::$request_cache[ $cache_key ] = $result;
        return $result;
    }
    
    /**
     * Grup ve tarih verilerini optimize edilmiş şekilde alır.
     */
    public static function get_groups_and_dates() {
        $cache_key = 'groups_and_dates';
        if ( isset( self::$request_cache[ $cache_key ] ) ) {
            return self::$request_cache[ $cache_key ];
        }
        
        $result = [
            'groups' => KNSDD_Data::get_groups(),
            'dates' => KNSDD_Data::get_all_group_dates()
        ];
        
        self::$request_cache[ $cache_key ] = $result;
        return $result;
    }
}
