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

/**
 * KNSDD_Campaigns Class
 *
 * Gelişmiş kampanya türlerinin (X Al Y Öde vb.) mantığını yönetir.
 * Bu sınıf, indirimleri bir ücret olarak eklemek yerine doğrudan sepet öğelerinin fiyatlarını değiştirir.
 */
class KNSDD_Campaigns {

    /**
     * Belirli bir kurala göre sepetteki uygun ürünlere kampanya uygular.
     *
     * @param WC_Cart $cart WooCommerce sepet nesnesi.
     * @param array $rule Uygulanacak kural.
     * @param array $matching_items Bu kurala uyan sepet öğelerinin dizisi.
     */
    public static function apply( $cart, $rule, $matching_items ) {
        if ( empty( $rule['campaign_type'] ) ) {
            return;
        }

        // BOGO kampanyaları matching_items gerektirmez (sepet bazlı çalışır)
        $is_bogo = ( $rule['campaign_type'] === 'buy_x_get_y_discount' );
        
        if ( ! $is_bogo && empty( $matching_items ) ) {
            return;
        }

        switch ( $rule['campaign_type'] ) {
            case 'buy_x_pay_y':
                self::apply_buy_x_pay_y( $rule, $matching_items );
                break;
            case 'nth_percent_off':
                self::apply_nth_percent_off( $rule, $matching_items );
                break;
            case 'buy_x_get_y_discount':
                self::apply_buy_x_get_y_discount( $rule, WC()->cart );
                break;
            // Gelecekte yeni kampanya türleri için buraya case'ler eklenebilir.
        }
    }

    /**
     * "X Al, Y Öde" kampanyasını uygular.
     *
     * @param array $rule Kampanya kuralı.
     * @param array $matching_items Kurala uyan sepet öğeleri.
     */
    private static function apply_buy_x_pay_y( $rule, $matching_items ) {
        $buy_x = isset( $rule['buy_x'] ) ? (int) $rule['buy_x'] : 0;
        $pay_y = isset( $rule['pay_y'] ) ? (int) $rule['pay_y'] : 0;

        // Ayarlar geçersizse veya alınacak miktar ödenecekten azsa işlem yapma.
        if ( $buy_x <= 0 || $pay_y < 0 || $buy_x <= $pay_y ) {
            return;
        }
        
        // Satır bazlı uygulama: Her ürün satırını bağımsız değerlendir.
        // Karmaşıklık: O(n) — sıralama veya havuzlama yok, DB sorgusu yok.
        $applied_any = false;
        $free_per_set = max( 0, $buy_x - $pay_y );

        foreach ( $matching_items as $item_key => $item ) {
            $quantity_in_item = (int) $item['quantity'];
            if ( $quantity_in_item < $buy_x ) {
                // Bu satırda tam set yoksa indirim uygulanmaz.
                continue;
            }

            $full_sets = intdiv( $quantity_in_item, $buy_x );
            if ( $full_sets <= 0 ) {
                continue;
            }

            $freebies            = $full_sets * $free_per_set;             // Bedava adet (satır içinde)
            $payable_in_sets     = $full_sets * $pay_y;                    // Setlerde ödenecek adet
            $leftovers           = $quantity_in_item - ( $full_sets * $buy_x );
            $total_payable_units = $payable_in_sets + $leftovers;          // Toplam ödenecek adet

            // Orijinal fiyatı bir kez sakla
            $original_price = (float) $item['data']->get_price();
            if ( ! $item['data']->get_meta('_knsdd_original_price') ) {
                $item['data']->add_meta_data('_knsdd_original_price', $original_price, true);
            }

            // Oran: ödenecek_adet / toplam_adet
            $ratio = $total_payable_units / max( 1, $quantity_in_item );
            $new_price = $original_price * $ratio;

            if ( $new_price < $original_price ) {
                $item['data']->set_price( $new_price );
                $applied_any = true;

                // Takip için meta verileri yaz
                if ( isset( WC()->cart->cart_contents[ $item_key ] ) ) {
                    $line_discount = ( $original_price - $new_price ) * $quantity_in_item;

                    WC()->cart->cart_contents[ $item_key ]['knsdd_rule_id'] = $rule['rule_id'];
                    if ( isset( $rule['group'] ) ) {
                        WC()->cart->cart_contents[ $item_key ]['knsdd_group'] = $rule['group'];
                    }
                    WC()->cart->cart_contents[ $item_key ]['knsdd_original_unit_price']   = $original_price;
                    WC()->cart->cart_contents[ $item_key ]['knsdd_discounted_unit_price'] = $new_price;
                    WC()->cart->cart_contents[ $item_key ]['knsdd_line_discount']         = $line_discount;
                }
            }
        }

        // Tutarlılık: Uygulama yapıldıysa session'a son uygulanan kuralı/grubu yaz
        if ( $applied_any ) {
            WC()->session->set( 'knsdd_applied_rule_id', $rule['rule_id'] );
            if ( isset( $rule['group'] ) ) {
                WC()->session->set( 'knsdd_applied_group', $rule['group'] );
            }
        }
    }

    /**
     * N'inci üründe % indirim kampanyasını uygular (satır bazlı).
     * Her satır için floor(q/nth) adet birime uygulanacak yüzde indirimi,
     * birim fiyata orantısal olarak dağıtır; havuz/sıralama yapılmaz.
     */
    private static function apply_nth_percent_off( $rule, $matching_items ) {
        $nth = isset( $rule['nth'] ) ? (int) $rule['nth'] : 0;
        if ( $nth <= 0 ) { return; }

        // Determine discount type/value (explicit)
        $dtype = isset( $rule['discount_type'] ) ? (string) $rule['discount_type'] : '';
        $dval  = isset( $rule['discount_value'] ) ? (float) $rule['discount_value'] : null;
        if ( $dtype !== 'amount' && $dtype !== 'percentage' ) { return; }
        if ( ! is_finite( $dval ) || $dval <= 0 ) { return; }

        // Satır bazlı uygulama: Her satır kendi nth indirimini alır. O(k), DB yok.
        $applied_any = false;
        $percent_ratio = $dtype === 'percentage' ? max( 0.0, min( 100.0, $dval ) ) / 100.0 : 0.0;

        foreach ( $matching_items as $item_key => $item ) {
            $quantity = (int) $item['quantity'];
            if ( $quantity < $nth ) { continue; }

            $original_price = (float) $item['data']->get_price();
            $discounted_units = intdiv( $quantity, $nth ); // Bu satırda indirime giren birim sayısı
            if ( $discounted_units <= 0 ) { continue; }

            if ( $dtype === 'percentage' ) {
                // Oran: 1 - percent * (discounted_units / quantity)
                $ratio = 1.0 - ( $percent_ratio * ( $discounted_units / max( 1, $quantity ) ) );
                $ratio = max( 0.0, min( 1.0, $ratio ) );
                $new_price = $original_price * $ratio;
            } else { // amount
                // Satır toplam indirimi: amount * discounted_units; birim başına eşit dağıt
                $per_unit_cut = ( $dval * $discounted_units ) / max( 1, $quantity );
                $new_price = max( 0.0, $original_price - $per_unit_cut );
            }

            if ( $new_price < $original_price ) {
                // Orijinal fiyatı sakla
                if ( ! $item['data']->get_meta('_knsdd_original_price') ) {
                    $item['data']->add_meta_data('_knsdd_original_price', $original_price, true);
                }

                $item['data']->set_price( $new_price );
                $applied_any = true;

                // Takip için meta ekle
                if ( isset( WC()->cart->cart_contents[ $item_key ] ) ) {
                    $line_discount = ( $original_price - $new_price ) * $quantity;
                    WC()->cart->cart_contents[ $item_key ]['knsdd_rule_id'] = $rule['rule_id'];
                    if ( isset( $rule['group'] ) ) {
                        WC()->cart->cart_contents[ $item_key ]['knsdd_group'] = $rule['group'];
                    }
                    WC()->cart->cart_contents[ $item_key ]['knsdd_original_unit_price'] = $original_price;
                    WC()->cart->cart_contents[ $item_key ]['knsdd_discounted_unit_price'] = $new_price;
                    WC()->cart->cart_contents[ $item_key ]['knsdd_line_discount'] = $line_discount;
                }
            }
        }

        if ( $applied_any ) {
            WC()->session->set( 'knsdd_applied_rule_id', $rule['rule_id'] );
            if ( isset( $rule['group'] ) ) {
                WC()->session->set( 'knsdd_applied_group', $rule['group'] );
            }
        }
    }

    /**
     * "A Al, B'ye İndirim" kampanyasını uygular (cross-product BOGO).
     * Tetikleyici ürünler/kategoriler sepette yeterli miktarda varsa,
     * hedef ürünler/kategorilere indirim uygular.
     *
     * @param array $rule Kampanya kuralı.
     * @param WC_Cart $cart WooCommerce sepet nesnesi.
     */
    private static function apply_buy_x_get_y_discount( $rule, $cart ) {
        if ( ! $cart || $cart->is_empty() ) {
            return;
        }

        $trigger_type = isset( $rule['trigger_type'] ) ? $rule['trigger_type'] : 'product';
        $trigger_quantity = isset( $rule['trigger_quantity'] ) ? (int) $rule['trigger_quantity'] : 1;
        $target_type = isset( $rule['target_type'] ) ? $rule['target_type'] : 'product';
        $target_quantity = isset( $rule['target_quantity'] ) ? (int) $rule['target_quantity'] : 1;
        $discount_type = isset( $rule['discount_type'] ) ? $rule['discount_type'] : 'percentage';
        $discount_value = isset( $rule['discount_value'] ) ? (float) $rule['discount_value'] : 0;

        if ( $trigger_quantity < 1 || $target_quantity < 1 ) {
            return;
        }

        // 1. Sepetten trigger ve target öğeleri ayır
        $trigger_items = [];
        $trigger_keys = []; // Tetikleyici ürünlerin key'leri (hedeften hariç tutmak için)
        $target_items = [];

        foreach ( $cart->get_cart() as $item_key => $item ) {
            $product_id = isset( $item['product_id'] ) ? (int) $item['product_id'] : 0;
            $variation_id = isset( $item['variation_id'] ) ? (int) $item['variation_id'] : 0;
            $check_id = $variation_id > 0 ? $variation_id : $product_id;

            // Trigger kontrolü
            if ( self::item_matches_scope( $check_id, $product_id, $trigger_type, $rule, 'trigger' ) ) {
                $trigger_items[] = [
                    'key' => $item_key,
                    'item' => $item,
                    'quantity' => (int) $item['quantity']
                ];
                $trigger_keys[] = $item_key; // Key'i kaydet
            }
        }
        
        // Hedef ürünleri ayrı döngüde topla (trigger'lardan sonra, hariç tutmak için)
        foreach ( $cart->get_cart() as $item_key => $item ) {
            // Tetikleyici olarak kullanılan ürünleri hedeften hariç tut
            if ( in_array( $item_key, $trigger_keys, true ) ) {
                continue;
            }
            
            $product_id = isset( $item['product_id'] ) ? (int) $item['product_id'] : 0;
            $variation_id = isset( $item['variation_id'] ) ? (int) $item['variation_id'] : 0;
            $check_id = $variation_id > 0 ? $variation_id : $product_id;

            // Target kontrolü
            if ( self::item_matches_scope( $check_id, $product_id, $target_type, $rule, 'target' ) ) {
                $target_items[] = [
                    'key' => $item_key,
                    'item' => $item,
                    'quantity' => (int) $item['quantity']
                ];
            }
        }

        // 2. Trigger koşulu sağlanıyor mu?
        $total_trigger_qty = array_sum( array_column( $trigger_items, 'quantity' ) );
        if ( $total_trigger_qty < $trigger_quantity ) {
            return; // Koşul sağlanmadı
        }

        // 3. Kaç set var?
        $sets = floor( $total_trigger_qty / $trigger_quantity );
        $discountable_qty = $sets * $target_quantity;

        if ( $discountable_qty <= 0 || empty( $target_items ) ) {
            return;
        }

        // Hedef ürünleri fiyata göre sırala (ucuzdan pahalıya)
        // Bu sayede indirim en ucuz hedef ürüne uygulanır (sektör standardı)
        usort( $target_items, function( $a, $b ) {
            $price_a = isset( $a['item']['data'] ) ? (float) $a['item']['data']->get_price() : 0;
            $price_b = isset( $b['item']['data'] ) ? (float) $b['item']['data']->get_price() : 0;
            return $price_a <=> $price_b; // Ucuzdan pahalıya
        });

        // 4. Hedef ürünlere indirim uygula
        $applied_qty = 0;
        $applied_any = false;

        foreach ( $target_items as $target ) {
            if ( $applied_qty >= $discountable_qty ) {
                break;
            }

            $item = $target['item'];
            $item_key = $target['key'];
            $item_qty = $target['quantity'];
            $qty_to_discount = min( $item_qty, $discountable_qty - $applied_qty );

            // Orijinal fiyatı sakla
            $original_price = (float) $item['data']->get_price();
            if ( ! $item['data']->get_meta( '_knsdd_original_price' ) ) {
                $item['data']->add_meta_data( '_knsdd_original_price', $original_price, true );
            }

            // İndirim hesapla
            $discount_per_unit = 0;
            if ( $discount_type === 'percentage' || $discount_type === 'free' ) {
                $percent = $discount_type === 'free' ? 100 : $discount_value;
                $discount_per_unit = $original_price * ( $percent / 100 );
            } elseif ( $discount_type === 'amount' ) {
                $discount_per_unit = min( $discount_value, $original_price );
            }

            // Yeni fiyat hesapla (orantısal)
            $discounted_units = $qty_to_discount;
            $normal_units = $item_qty - $discounted_units;
            $total_price = ( $normal_units * $original_price ) + ( $discounted_units * ( $original_price - $discount_per_unit ) );
            $new_price = $total_price / max( 1, $item_qty );

            if ( $new_price < $original_price ) {
                $item['data']->set_price( $new_price );
                $applied_any = true;

                // Meta verileri kaydet
                if ( isset( $cart->cart_contents[ $item_key ] ) ) {
                    $line_discount = ( $original_price - $new_price ) * $item_qty;

                    $cart->cart_contents[ $item_key ]['knsdd_rule_id'] = $rule['rule_id'];
                    if ( isset( $rule['group'] ) ) {
                        $cart->cart_contents[ $item_key ]['knsdd_group'] = $rule['group'];
                    }
                    $cart->cart_contents[ $item_key ]['knsdd_original_unit_price']   = $original_price;
                    $cart->cart_contents[ $item_key ]['knsdd_discounted_unit_price'] = $new_price;
                    $cart->cart_contents[ $item_key ]['knsdd_line_discount']         = $line_discount;
                }
            }

            $applied_qty += $qty_to_discount;
        }

        // Session'a kaydet
        if ( $applied_any ) {
            WC()->session->set( 'knsdd_applied_rule_id', $rule['rule_id'] );
            if ( isset( $rule['group'] ) ) {
                WC()->session->set( 'knsdd_applied_group', $rule['group'] );
            }
        }
    }

    /**
     * Bir sepet öğesinin trigger/target kapsamına uyup uymadığını kontrol eder.
     *
     * YENİ MANTIK:
     * - Sadece ürün varsa: Ürün listesinde olmalı
     * - Sadece kategori varsa: Kategoriye ait olmalı
     * - Hem kategori hem ürün varsa: Ürün listesinde OLMALI VE kategoriye ait OLMALI (AND mantığı)
     *
     * @param int $check_id Kontrol edilecek ürün ID (variation varsa variation_id, yoksa product_id).
     * @param int $product_id Ana ürün ID.
     * @param string $scope_type 'product' veya 'category' (artık kullanılmıyor, geriye uyumluluk için kalabilir).
     * @param array $rule Kural verisi.
     * @param string $prefix 'trigger' veya 'target'.
     * @return bool
     */
    private static function item_matches_scope( $check_id, $product_id, $scope_type, $rule, $prefix ) {
        $products = isset( $rule[ $prefix . '_products' ] ) && is_array( $rule[ $prefix . '_products' ] ) 
            ? $rule[ $prefix . '_products' ] 
            : [];
        $category_id = isset( $rule[ $prefix . '_category' ] ) ? (int) $rule[ $prefix . '_category' ] : 0;
        
        $has_products = ! empty( $products );
        $has_category = $category_id > 0;
        
        // Hiçbiri yoksa false
        if ( ! $has_products && ! $has_category ) {
            return false;
        }
        
        // Ürün kontrolü
        $in_product_list = false;
        if ( $has_products ) {
            $in_product_list = in_array( $check_id, $products, true ) || in_array( $product_id, $products, true );
        }
        
        // Kategori kontrolü (hiyerarşik destek)
        $in_category = false;
        if ( $has_category ) {
            $product_cats = wc_get_product_term_ids( $check_id, 'product_cat' );
            if ( empty( $product_cats ) && $product_id > 0 ) {
                // Varyasyon için parent kategorilerini kontrol et
                $product_cats = wc_get_product_term_ids( $product_id, 'product_cat' );
            }
            
            // Ürün kategorilerini genişlet (alt → üst)
            if ( ! empty( $product_cats ) ) {
                $expanded_product_cats = array_map( 'intval', $product_cats );
                foreach ( $product_cats 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 );
                $in_category = in_array( $category_id, $expanded_product_cats, true );
            }
        }
        
        // Karar mantığı
        if ( $has_products && $has_category ) {
            // Her ikisi de varsa: AND mantığı (ürün listesinde VE kategoriye ait)
            return $in_product_list && $in_category;
        } elseif ( $has_products ) {
            // Sadece ürün varsa
            return $in_product_list;
        } else {
            // Sadece kategori varsa
            return $in_category;
        }
    }
}