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

class KNSDD_Checkout_Protection {
    const LOCK_TTL = 120; // seconds

    public static function init() {
        // Backend idempotency
        add_action( 'woocommerce_before_checkout_process', [ __CLASS__, 'guard_begin' ], 0 );
        add_action( 'woocommerce_checkout_order_processed', [ __CLASS__, 'guard_mark_done' ], 10, 1 );
        add_action( 'woocommerce_after_checkout_validation', [ __CLASS__, 'maybe_unlock_on_error' ], 10, 2 );

        // Cross-session per-rule pending reservation validation
        add_action( 'woocommerce_after_checkout_validation', [ __CLASS__, 'validate_rule_pending' ], 5, 2 );

        // Sert kullanım limiti/doğrulama (per-customer limit ve grup tek-kullanım)
        add_action( 'woocommerce_after_checkout_validation', [ __CLASS__, 'validate_usage_limits' ], 6, 2 );

        // Frontend guard script
        add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_frontend_guard' ], 100 );
    }

    /**
     * Returns a stable customer identifier and a per-attempt token.
     */
    private static function get_identifiers() {
        $user_id = is_user_logged_in() ? get_current_user_id() : 0;
        $email = '';
        if ( function_exists( 'WC' ) && WC()->customer ) {
            $email = sanitize_email( WC()->customer->get_email() );
            if ( empty( $email ) ) {
                $email = sanitize_email( WC()->customer->get_billing_email() );
            }
        }
        if ( empty( $email ) && $user_id > 0 ) {
            $u = get_user_by( 'id', $user_id );
            if ( $u && ! empty( $u->user_email ) ) { $email = sanitize_email( $u->user_email ); }
        }

        // Current attempt token to distinguish same-session revalidations from parallel sessions
        $token = '';
        if ( function_exists( 'WC' ) && WC()->session ) {
            $token = (string) WC()->session->get( 'knsdd_checkout_token' );
            if ( $token === '' ) {
                $token = wp_generate_uuid4();
                WC()->session->set( 'knsdd_checkout_token', $token );
            }
        }

        $id_key = $user_id > 0 ? 'uid:' . $user_id : ( $email !== '' ? 'mail:' . $email : 'sid:' . ( function_exists('WC') && WC()->session && method_exists(WC()->session,'get_session_id') ? WC()->session->get_session_id() : '' ) );
        return [ $id_key, $token ];
    }

    private static function get_lock_key() {
        if ( ! function_exists( 'WC' ) || ! WC()->session || ! WC()->cart ) {
            return '';
        }
        $session = WC()->session;
        $sid = '';
        if ( method_exists( $session, 'get_session_id' ) ) {
            $sid = (string) $session->get_session_id();
        } elseif ( method_exists( $session, 'get_customer_id' ) ) {
            $sid = (string) $session->get_customer_id();
        } else {
            $sid = (string) $session->get( 'customer_id' );
        }
        $hash = '';
        if ( method_exists( WC()->cart, 'get_cart_hash' ) ) {
            $hash = (string) WC()->cart->get_cart_hash();
        }
        if ( empty( $sid ) && is_user_logged_in() ) {
            $sid = 'u_' . get_current_user_id();
        }
        if ( empty( $sid ) && empty( $hash ) ) {
            return '';
        }
        return 'knsdd_checkout_lock_' . md5( $sid . '|' . $hash );
    }

    /**
     * Collect rule IDs currently applied to the cart (line items + cart total rule via session).
     */
    private static function get_cart_rule_ids() {
        $rule_ids = [];
        if ( function_exists( 'WC' ) && WC()->cart ) {
            foreach ( (array) WC()->cart->get_cart() as $key => $item ) {
                $rid = null;
                if ( isset( $item['knsdd_rule_id'] ) && $item['knsdd_rule_id'] ) {
                    $rid = $item['knsdd_rule_id'];
                } elseif ( isset( $item['_knsdd_rule_id'] ) && $item['_knsdd_rule_id'] ) {
                    $rid = $item['_knsdd_rule_id'];
                }
                if ( $rid ) { $rule_ids[ (string) $rid ] = true; }
            }
        }
        if ( function_exists( 'WC' ) && WC()->session ) {
            $sid_rule = WC()->session->get( 'knsdd_applied_rule_id' );
            if ( ! empty( $sid_rule ) ) { $rule_ids[ (string) $sid_rule ] = true; }
        }
        return array_keys( $rule_ids );
    }

    /**
     * Collect applied group names from cart/session for group-level enforcement.
     */
    private static function get_cart_groups() {
        $groups = [];
        if ( function_exists( 'WC' ) && WC()->cart ) {
            foreach ( (array) WC()->cart->get_cart() as $key => $item ) {
                $grp = null;
                if ( isset( $item['knsdd_group'] ) && $item['knsdd_group'] ) {
                    $grp = $item['knsdd_group'];
                } elseif ( isset( $item['_knsdd_group'] ) && $item['_knsdd_group'] ) {
                    $grp = $item['_knsdd_group'];
                }
                if ( $grp ) { $groups[ (string) $grp ] = true; }
            }
        }
        if ( function_exists( 'WC' ) && WC()->session ) {
            $sid_group = WC()->session->get( 'knsdd_applied_group' );
            if ( ! empty( $sid_group ) ) { $groups[ (string) $sid_group ] = true; }
        }
        return array_keys( $groups );
    }

    /** Debug helper - disabled in production */
    private static function debug( $label, $data = null ) {
        // Debug logging devre dışı - production için kaldırıldı
        return;
    }

    public static function guard_begin() {
        $key = self::get_lock_key();
        if ( empty( $key ) ) { return; }

        $entry = get_transient( $key );
        if ( $entry && is_array( $entry ) ) {
            if ( isset( $entry['status'] ) && 'done' === $entry['status'] && ! empty( $entry['order_id'] ) ) {
                wc_add_notice( sprintf( __( 'Siparişiniz zaten alındı. Sipariş #%d', 'kns-dynamic-discounts-for-woocommerce' ), absint( $entry['order_id'] ) ), 'notice' );
            } else {
                wc_add_notice( __( 'Siparişiniz işleniyor, lütfen sayfayı yenilemeyin veya tekrar tıklamayın.', 'kns-dynamic-discounts-for-woocommerce' ), 'error' );
            }
            return; // Leave notices for WC to return failure via AJAX
        }

        // Set processing lock
        set_transient( $key, [ 'status' => 'processing', 't' => time() ], self::LOCK_TTL );

        // Reserve applied rules for this customer to avoid cross-session duplicates racing
        list( $id_key, $token ) = self::get_identifiers();
        $rules = self::get_cart_rule_ids();
        foreach ( $rules as $rid ) {
            $rk = 'knsdd_rule_pending_' . md5( $rid . '|' . $id_key );
            // Store token so our own validation doesn't block the same attempt
            set_transient( $rk, [ 'token' => $token, 't' => time() ], self::LOCK_TTL );
        }
    }

    public static function guard_mark_done( $order_id ) {
        $key = self::get_lock_key();
        if ( empty( $key ) ) { return; }
        set_transient( $key, [ 'status' => 'done', 'order_id' => absint( $order_id ), 't' => time() ], self::LOCK_TTL );

        // Clear rule reservations on success
        list( $id_key, /*$token*/ ) = self::get_identifiers();
        $rules = self::get_cart_rule_ids();
        foreach ( $rules as $rid ) {
            $rk = 'knsdd_rule_pending_' . md5( $rid . '|' . $id_key );
            delete_transient( $rk );
        }
    }

    public static function maybe_unlock_on_error( $data, $errors ) {
        if ( is_wp_error( $errors ) && $errors->get_error_code() ) {
            // old signature guard
        }
        // Woo after_validation passes an errors object implementing get_error_count
        if ( is_object( $errors ) && method_exists( $errors, 'get_error_count' ) && $errors->get_error_count() > 0 ) {
            $key = self::get_lock_key();
            if ( $key ) { delete_transient( $key ); }

            // Clear rule reservations if validation failed
            list( $id_key, /*$token*/ ) = self::get_identifiers();
            $rules = self::get_cart_rule_ids();
            foreach ( $rules as $rid ) {
                $rk = 'knsdd_rule_pending_' . md5( $rid . '|' . $id_key );
                delete_transient( $rk );
            }
        }
    }

    /**
     * If another concurrent checkout by the same customer/email has reserved the same rule,
     * block this order to prevent double-usage before DB logs are written.
     */
    public static function validate_rule_pending( $data, $errors ) {
        // Errors object can be WP_Error or WC_Checkout instance error handler; we only add if available
        if ( ! is_object( $errors ) || ! method_exists( $errors, 'add' ) ) { return; }
        list( $id_key, $token ) = self::get_identifiers();
        if ( $id_key === '' ) { return; }
        $rules = self::get_cart_rule_ids();
        foreach ( $rules as $rid ) {
            $rk = 'knsdd_rule_pending_' . md5( $rid . '|' . $id_key );
            $entry = get_transient( $rk );
            if ( $entry && is_array( $entry ) ) {
                $other = isset( $entry['token'] ) ? (string) $entry['token'] : '';
                if ( $other !== '' && $other !== $token ) {
                    $errors->add( 'knsdd_rule_pending', __( 'Bu indirim kuralı için başka bir ödeme işleminiz sürüyor. Lütfen birkaç saniye sonra tekrar deneyin.', 'kns-dynamic-discounts-for-woocommerce' ) );
                    // Do not break; list all conflicts
                }
            }
        }
    }

    /**
     * Checkout doğrulamasında per-customer limit ve grup tek-kullanım kurallarını kesin olarak uygula.
     */
    public static function validate_usage_limits( $data, $errors ) {
        if ( ! is_object( $errors ) || ! method_exists( $errors, 'add' ) ) { return; }
        // Kimlik
        $user_id = is_user_logged_in() ? get_current_user_id() : 0;
        $email = '';
        // 1) Checkout form datasından e-posta (misafirlerde kritik)
        if ( is_array( $data ) ) {
            $posted_email = '';
            if ( isset( $data['billing_email'] ) ) { $posted_email = $data['billing_email']; }
            elseif ( isset( $_POST['billing_email'] ) ) { $posted_email = wp_unslash( $_POST['billing_email'] ); }
            $email = sanitize_email( $posted_email );
        }
        // 2) WC müşteri objesinden
        if ( empty( $email ) && function_exists( 'WC' ) && WC()->customer ) {
            $email = sanitize_email( WC()->customer->get_email() );
            if ( empty( $email ) ) { $email = sanitize_email( WC()->customer->get_billing_email() ); }
        }
        if ( empty( $email ) && $user_id > 0 ) {
            $u = get_user_by( 'id', $user_id );
            if ( $u && ! empty( $u->user_email ) ) { $email = sanitize_email( $u->user_email ); }
        }

        // Sepette uygulanan kural ve gruplar
        $rule_ids = self::get_cart_rule_ids();
        $groups   = self::get_cart_groups();
        self::debug( 'validate_usage_limits.identifiers', [ 'user_id' => $user_id, 'email' => $email ] );
        self::debug( 'validate_usage_limits.cart_meta_before_fallback', [ 'rule_ids' => $rule_ids, 'groups' => $groups ] );

        if ( empty( $rule_ids ) && empty( $groups ) ) { return; }

        // Grup kilidi kontrolü kaldırıldı - artık sadece per_customer_limit kontrolü yapılıyor

        if ( empty( $rule_ids ) ) { return; }

        // Kural yapılarını bul (rule_id -> rule)
        $rule_map = class_exists('KNSDD_Data') && method_exists('KNSDD_Data', 'get_rules_by_ids')
            ? KNSDD_Data::get_rules_by_ids( $rule_ids )
            : [];

        // Tier grup ID'lerini oluştur (aynı ürün/kategori kapsamındaki kurallar için ortak havuz)
        $usage_rule_ids = [];
        foreach ( $rule_ids as $rid ) {
            $group_ids = class_exists('KNSDD_Data') && method_exists( 'KNSDD_Data', 'get_tier_group_rule_ids' )
                ? KNSDD_Data::get_tier_group_rule_ids( $rid )
                : array( $rid );
            foreach ( (array) $group_ids as $gid ) {
                $usage_rule_ids[ (string) $gid ] = true;
            }
        }
        $usage_rule_ids = array_keys( $usage_rule_ids );

        // Kullanım sayımları (kademe grubu bazında)
        $usage_map = KNSDD_Data::get_usage_for_multiple_rules( $usage_rule_ids );
        $email_usage_map = [];
        if ( ! empty( $email ) ) {
            $email_usage_map = KNSDD_Data::get_usage_for_multiple_rules_by_email( $usage_rule_ids, $email );
        }
        self::debug( 'validate_usage_limits.rule_ids', $rule_ids );
        self::debug( 'validate_usage_limits.usage_map', $usage_map );
        self::debug( 'validate_usage_limits.email_usage_map', $email_usage_map );

        foreach ( $rule_ids as $rid ) {
            $rule = isset( $rule_map[ $rid ] ) ? $rule_map[ $rid ] : null;
            if ( ! $rule ) { continue; }
            
            // Tier grup ID'lerini al
            $group_rule_ids = class_exists('KNSDD_Data') && method_exists( 'KNSDD_Data', 'get_tier_group_rule_ids' )
                ? KNSDD_Data::get_tier_group_rule_ids( $rid )
                : array( $rid );

            // Toplam kullanım limiti kontrolü (kademe grubu bazında)
            $total_limit = (int) ( $rule['total_limit'] ?? 0 );
            if ( $total_limit > 0 ) {
                $group_total = 0;
                $group_members_only_total = 0;
                foreach ( (array) $group_rule_ids as $gid ) {
                    $u = $usage_map[ $gid ] ?? [ 'users' => [], 'total' => 0, 'members_only_total' => 0 ];
                    $group_total += isset( $u['total'] ) ? (int) $u['total'] : 0;
                    $group_members_only_total += isset( $u['members_only_total'] ) ? (int) $u['members_only_total'] : 0;
                }

                // Eğer "Sadece Üyeler" seçili ise, sadece üye kullanımlarını say
                $current_usage = ! empty( $rule['login_required'] ) ? $group_members_only_total : $group_total;
                
                if ( $current_usage >= $total_limit ) {
                    $errors->add( 'knsdd_total_limit', __( 'Bu kampanyanın toplam kullanım limiti dolmuştur.', 'kns-dynamic-discounts-for-woocommerce' ) );
                    continue;
                }
            }
            
            // Müşteri başına kullanım limiti kontrolü (kademe grubu bazında)
            $per_customer_limit = (int) ( $rule['per_customer_limit'] ?? 0 );
            self::debug( 'validate_usage_limits.rule_check', [ 'rid' => $rid, 'per_customer_limit' => $per_customer_limit, 'total_limit' => $total_limit ] );
            if ( $per_customer_limit <= 0 ) { continue; }

            $group_user_usage = 0;
            $group_email_usage = 0;
            foreach ( (array) $group_rule_ids as $gid ) {
                $u = $usage_map[ $gid ] ?? [ 'users' => [], 'total' => 0 ];
                $used_by_user  = ( $user_id > 0 ) ? (int) ( $u['users'][ $user_id ] ?? 0 ) : 0;
                $used_by_email = ( ! empty( $email ) ) ? (int) ( $email_usage_map[ $gid ] ?? 0 ) : 0;
                $group_user_usage  += $used_by_user;
                $group_email_usage += $used_by_email;
            }

            $already_used = max( $group_user_usage, $group_email_usage );
            self::debug( 'validate_usage_limits.used_counts', [ 'rid' => $rid, 'user' => $group_user_usage, 'email' => $group_email_usage, 'already' => $already_used ] );
            if ( $already_used >= $per_customer_limit ) {
                $errors->add( 'knsdd_per_customer_limit', __( 'Bu indirim kuralını izin verilen kullanım sayısını aştığınız için kullanamazsınız.', 'kns-dynamic-discounts-for-woocommerce' ) );
            }
        }
    }

    public static function enqueue_frontend_guard() {
        if ( function_exists( 'is_checkout' ) && is_checkout() ) {
            wp_enqueue_script(
                'knsdd-checkout-guard',
                plugins_url( '../../../assets/js/checkout-guard.js', __FILE__ ),
                [ 'jquery' ],
                defined('KNSDD_VERSION') ? KNSDD_VERSION : '1.0.0',
                true
            );
            wp_localize_script( 'knsdd-checkout-guard', 'KNSDD_CheckoutGuard', [
                'processingText' => __( 'İşleniyor...', 'kns-dynamic-discounts-for-woocommerce' )
            ] );
        }
    }
}
