<?php
/**
 * GGM Commerce Discounts & Vouchers Class
 * Handles discount codes, vouchers, and gift cards
 *
 * @package GGM_Commerce
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

/**
 * Discounts class for managing discount codes and vouchers
 */
class GGM_Commerce_Discounts {

    /**
     * Premium widget slug for license checking
     */
    const PREMIUM_SLUG = 'discount-vouchers';

    /**
     * Discount types
     */
    const TYPE_PERCENTAGE = 'percentage';
    const TYPE_FIXED = 'fixed_amount';
    const TYPE_VOUCHER = 'voucher';

    /**
     * Singleton instance
     *
     * @var GGM_Commerce_Discounts
     */
    private static $instance = null;

    /**
     * Get singleton instance
     *
     * @return GGM_Commerce_Discounts
     */
    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Check if discounts feature is activated
     *
     * @return bool
     */
    public static function is_activated() {
        if ( ! class_exists( 'GGM_Commerce_License' ) ) {
            return false;
        }
        return GGM_Commerce_License::instance()->is_widget_activated( self::PREMIUM_SLUG );
    }

    /**
     * Constructor
     */
    private function __construct() {
        // Only register hooks if feature is activated.
        if ( self::is_activated() ) {
            $this->register_hooks();
        }
    }

    /**
     * Register hooks
     */
    private function register_hooks() {
        // AJAX handlers.
        add_action( 'wp_ajax_ggmc_validate_discount', array( $this, 'ajax_validate_discount' ) );
        add_action( 'wp_ajax_nopriv_ggmc_validate_discount', array( $this, 'ajax_validate_discount' ) );
        add_action( 'wp_ajax_ggmc_apply_discount', array( $this, 'ajax_apply_discount' ) );
        add_action( 'wp_ajax_nopriv_ggmc_apply_discount', array( $this, 'ajax_apply_discount' ) );
        add_action( 'wp_ajax_ggmc_remove_discount', array( $this, 'ajax_remove_discount' ) );
        add_action( 'wp_ajax_nopriv_ggmc_remove_discount', array( $this, 'ajax_remove_discount' ) );

        // Admin AJAX handlers.
        add_action( 'wp_ajax_ggmc_create_discount', array( $this, 'ajax_create_discount' ) );
        add_action( 'wp_ajax_ggmc_update_discount', array( $this, 'ajax_update_discount' ) );
        add_action( 'wp_ajax_ggmc_delete_discount', array( $this, 'ajax_delete_discount' ) );
        add_action( 'wp_ajax_ggmc_get_discount', array( $this, 'ajax_get_discount' ) );
        add_action( 'wp_ajax_ggmc_bulk_generate_vouchers', array( $this, 'ajax_bulk_generate_vouchers' ) );

        // Order completion hook for gift card products.
        add_action( 'ggmc_order_status_completed', array( $this, 'process_gift_card_order_items' ) );
        add_action( 'ggmc_order_status_processing', array( $this, 'process_gift_card_order_items' ) );
    }

    /**
     * Create a new discount
     *
     * @param array $data Discount data.
     * @return array Result with success status and discount ID or error.
     */
    public function create_discount( $data ) {
        global $wpdb;

        // Validate required fields.
        if ( empty( $data['code'] ) || empty( $data['name'] ) ) {
            return array(
                'success' => false,
                'error'   => __( 'Code and name are required.', 'ggm-commerce' ),
            );
        }

        // Sanitize and normalize code.
        $code = strtoupper( sanitize_text_field( $data['code'] ) );

        // Check if code already exists.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $existing = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT id FROM {$wpdb->prefix}ggmc_discounts WHERE code = %s",
                $code
            )
        );

        if ( $existing ) {
            return array(
                'success' => false,
                'error'   => __( 'A discount with this code already exists.', 'ggm-commerce' ),
            );
        }

        // Prepare data for insert.
        $discount_type = isset( $data['discount_type'] ) ? sanitize_text_field( $data['discount_type'] ) : self::TYPE_PERCENTAGE;
        $amount = isset( $data['amount'] ) ? floatval( $data['amount'] ) : 0.00;

        $insert_data = array(
            'code'                   => $code,
            'name'                   => sanitize_text_field( $data['name'] ),
            'description'            => isset( $data['description'] ) ? sanitize_textarea_field( $data['description'] ) : '',
            'discount_type'          => $discount_type,
            'amount'                 => $amount,
            'usage_limit'            => isset( $data['usage_limit'] ) ? ( $data['usage_limit'] === '' ? null : absint( $data['usage_limit'] ) ) : null,
            'usage_limit_per_user'   => isset( $data['usage_limit_per_user'] ) ? ( $data['usage_limit_per_user'] === '' ? null : absint( $data['usage_limit_per_user'] ) ) : null,
            'minimum_order_amount'   => isset( $data['minimum_order_amount'] ) && $data['minimum_order_amount'] !== '' ? floatval( $data['minimum_order_amount'] ) : null,
            'maximum_discount_amount' => isset( $data['maximum_discount_amount'] ) && $data['maximum_discount_amount'] !== '' ? floatval( $data['maximum_discount_amount'] ) : null,
            'applies_to'             => isset( $data['applies_to'] ) ? sanitize_text_field( $data['applies_to'] ) : 'all',
            'product_ids'            => isset( $data['product_ids'] ) ? wp_json_encode( array_map( 'absint', (array) $data['product_ids'] ) ) : null,
            'category_ids'           => isset( $data['category_ids'] ) ? wp_json_encode( array_map( 'absint', (array) $data['category_ids'] ) ) : null,
            'exclude_product_ids'    => isset( $data['exclude_product_ids'] ) ? wp_json_encode( array_map( 'absint', (array) $data['exclude_product_ids'] ) ) : null,
            'exclude_category_ids'   => isset( $data['exclude_category_ids'] ) ? wp_json_encode( array_map( 'absint', (array) $data['exclude_category_ids'] ) ) : null,
            'valid_from'             => isset( $data['valid_from'] ) && ! empty( $data['valid_from'] ) ? sanitize_text_field( $data['valid_from'] ) : null,
            'valid_to'               => isset( $data['valid_to'] ) && ! empty( $data['valid_to'] ) ? sanitize_text_field( $data['valid_to'] ) : null,
            'free_shipping'          => isset( $data['free_shipping'] ) ? ( $data['free_shipping'] ? 1 : 0 ) : 0,
            'status'                 => isset( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'active',
            'created_by'             => get_current_user_id(),
        );

        // Handle voucher-specific fields.
        if ( self::TYPE_VOUCHER === $discount_type ) {
            $insert_data['initial_value'] = $amount;
            $insert_data['current_balance'] = $amount;
            $insert_data['single_use_voucher'] = isset( $data['single_use_voucher'] ) ? ( $data['single_use_voucher'] ? 1 : 0 ) : 0;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $inserted = $wpdb->insert(
            "{$wpdb->prefix}ggmc_discounts",
            $insert_data
        );

        if ( ! $inserted ) {
            return array(
                'success' => false,
                'error'   => __( 'Failed to create discount.', 'ggm-commerce' ),
            );
        }

        return array(
            'success'     => true,
            'discount_id' => $wpdb->insert_id,
            'message'     => __( 'Discount created successfully.', 'ggm-commerce' ),
        );
    }

    /**
     * Update an existing discount
     *
     * @param int   $id   Discount ID.
     * @param array $data Updated data.
     * @return array Result with success status.
     */
    public function update_discount( $id, $data ) {
        global $wpdb;

        $discount = $this->get_discount( $id );
        if ( ! $discount ) {
            return array(
                'success' => false,
                'error'   => __( 'Discount not found.', 'ggm-commerce' ),
            );
        }

        // Build update data.
        $update_data = array();
        $format = array();

        $string_fields = array( 'name', 'description', 'discount_type', 'applies_to', 'status' );
        foreach ( $string_fields as $field ) {
            if ( isset( $data[ $field ] ) ) {
                $update_data[ $field ] = sanitize_text_field( $data[ $field ] );
                $format[] = '%s';
            }
        }

        $float_fields = array( 'amount', 'minimum_order_amount', 'maximum_discount_amount' );
        foreach ( $float_fields as $field ) {
            if ( isset( $data[ $field ] ) ) {
                $update_data[ $field ] = $data[ $field ] === '' ? null : floatval( $data[ $field ] );
                $format[] = '%f';
            }
        }

        $int_fields = array( 'usage_limit', 'usage_limit_per_user', 'free_shipping', 'single_use_voucher' );
        foreach ( $int_fields as $field ) {
            if ( isset( $data[ $field ] ) ) {
                $update_data[ $field ] = $data[ $field ] === '' ? null : absint( $data[ $field ] );
                $format[] = '%d';
            }
        }

        $date_fields = array( 'valid_from', 'valid_to' );
        foreach ( $date_fields as $field ) {
            if ( isset( $data[ $field ] ) ) {
                $update_data[ $field ] = empty( $data[ $field ] ) ? null : sanitize_text_field( $data[ $field ] );
                $format[] = '%s';
            }
        }

        $json_fields = array( 'product_ids', 'category_ids', 'exclude_product_ids', 'exclude_category_ids' );
        foreach ( $json_fields as $field ) {
            if ( isset( $data[ $field ] ) ) {
                $update_data[ $field ] = wp_json_encode( array_map( 'absint', (array) $data[ $field ] ) );
                $format[] = '%s';
            }
        }

        if ( empty( $update_data ) ) {
            return array(
                'success' => false,
                'error'   => __( 'No data to update.', 'ggm-commerce' ),
            );
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $updated = $wpdb->update(
            "{$wpdb->prefix}ggmc_discounts",
            $update_data,
            array( 'id' => $id ),
            $format,
            array( '%d' )
        );

        return array(
            'success' => true,
            'message' => __( 'Discount updated successfully.', 'ggm-commerce' ),
        );
    }

    /**
     * Delete a discount
     *
     * @param int $id Discount ID.
     * @return array Result with success status.
     */
    public function delete_discount( $id ) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $deleted = $wpdb->delete(
            "{$wpdb->prefix}ggmc_discounts",
            array( 'id' => $id ),
            array( '%d' )
        );

        if ( ! $deleted ) {
            return array(
                'success' => false,
                'error'   => __( 'Failed to delete discount.', 'ggm-commerce' ),
            );
        }

        return array(
            'success' => true,
            'message' => __( 'Discount deleted successfully.', 'ggm-commerce' ),
        );
    }

    /**
     * Get a discount by ID
     *
     * @param int $id Discount ID.
     * @return object|null Discount object or null.
     */
    public function get_discount( $id ) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $discount = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_discounts WHERE id = %d",
                $id
            )
        );

        if ( $discount ) {
            $discount = $this->decode_discount_fields( $discount );
        }

        return $discount;
    }

    /**
     * Get a discount by code
     *
     * @param string $code Discount code.
     * @return object|null Discount object or null.
     */
    public function get_discount_by_code( $code ) {
        global $wpdb;

        $code = strtoupper( sanitize_text_field( $code ) );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $discount = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_discounts WHERE code = %s",
                $code
            )
        );

        if ( $discount ) {
            $discount = $this->decode_discount_fields( $discount );
        }

        return $discount;
    }

    /**
     * Decode JSON fields in discount object
     *
     * @param object $discount Discount object.
     * @return object Discount with decoded fields.
     */
    private function decode_discount_fields( $discount ) {
        $json_fields = array( 'product_ids', 'category_ids', 'exclude_product_ids', 'exclude_category_ids' );
        foreach ( $json_fields as $field ) {
            if ( ! empty( $discount->$field ) ) {
                $discount->$field = json_decode( $discount->$field, true );
            } else {
                $discount->$field = array();
            }
        }
        return $discount;
    }

    /**
     * List discounts with filtering
     *
     * @param array $args Query arguments.
     * @return array Array with discounts and pagination info.
     */
    public function list_discounts( $args = array() ) {
        global $wpdb;

        $defaults = array(
            'page'     => 1,
            'per_page' => 20,
            'status'   => '',
            'type'     => '',
            'search'   => '',
            'orderby'  => 'created_at',
            'order'    => 'DESC',
        );

        $args = wp_parse_args( $args, $defaults );

        $where = array( '1=1' );
        $params = array();

        if ( ! empty( $args['status'] ) ) {
            $where[] = 'status = %s';
            $params[] = $args['status'];
        }

        if ( ! empty( $args['type'] ) ) {
            $where[] = 'discount_type = %s';
            $params[] = $args['type'];
        }

        if ( ! empty( $args['search'] ) ) {
            $where[] = '(code LIKE %s OR name LIKE %s)';
            $search = '%' . $wpdb->esc_like( $args['search'] ) . '%';
            $params[] = $search;
            $params[] = $search;
        }

        $where_clause = implode( ' AND ', $where );

        // Get total count.
        $count_query = "SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_discounts WHERE {$where_clause}";
        if ( ! empty( $params ) ) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
            $total = $wpdb->get_var( $wpdb->prepare( $count_query, $params ) );
        } else {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
            $total = $wpdb->get_var( $count_query );
        }

        // Get discounts.
        $offset = ( $args['page'] - 1 ) * $args['per_page'];
        $orderby = in_array( $args['orderby'], array( 'code', 'name', 'discount_type', 'status', 'usage_count', 'created_at' ), true ) ? $args['orderby'] : 'created_at';
        $order = 'ASC' === strtoupper( $args['order'] ) ? 'ASC' : 'DESC';

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $query = "SELECT * FROM {$wpdb->prefix}ggmc_discounts WHERE {$where_clause} ORDER BY {$orderby} {$order} LIMIT %d OFFSET %d";
        $params[] = $args['per_page'];
        $params[] = $offset;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
        $discounts = $wpdb->get_results( $wpdb->prepare( $query, $params ) );

        foreach ( $discounts as &$discount ) {
            $discount = $this->decode_discount_fields( $discount );
        }

        return array(
            'discounts'   => $discounts,
            'total'       => (int) $total,
            'page'        => $args['page'],
            'per_page'    => $args['per_page'],
            'total_pages' => ceil( $total / $args['per_page'] ),
        );
    }

    /**
     * Validate a discount code
     *
     * @param string $code           Discount code.
     * @param float  $cart_total     Cart total.
     * @param string $customer_email Customer email.
     * @param array  $cart_items     Optional cart items for product/category checks.
     * @return array Validation result.
     */
    public function validate_discount_code( $code, $cart_total, $customer_email = '', $cart_items = array() ) {
        $discount = $this->get_discount_by_code( $code );

        if ( ! $discount ) {
            return array(
                'valid' => false,
                'error' => __( 'Invalid discount code.', 'ggm-commerce' ),
            );
        }

        // Check status.
        if ( 'active' !== $discount->status ) {
            return array(
                'valid' => false,
                'error' => __( 'This discount code is no longer active.', 'ggm-commerce' ),
            );
        }

        // Check date range.
        $now = current_time( 'mysql' );
        if ( $discount->valid_from && $now < $discount->valid_from ) {
            return array(
                'valid' => false,
                'error' => __( 'This discount code is not yet valid.', 'ggm-commerce' ),
            );
        }
        if ( $discount->valid_to && $now > $discount->valid_to ) {
            return array(
                'valid' => false,
                'error' => __( 'This discount code has expired.', 'ggm-commerce' ),
            );
        }

        // Check usage limit.
        if ( $discount->usage_limit && $discount->usage_count >= $discount->usage_limit ) {
            return array(
                'valid' => false,
                'error' => __( 'This discount code has reached its usage limit.', 'ggm-commerce' ),
            );
        }

        // Check per-user limit.
        if ( $discount->usage_limit_per_user && ! empty( $customer_email ) ) {
            $user_usage = $this->get_customer_usage( $discount->id, $customer_email );
            if ( $user_usage >= $discount->usage_limit_per_user ) {
                return array(
                    'valid' => false,
                    'error' => __( 'You have already used this discount code the maximum number of times.', 'ggm-commerce' ),
                );
            }
        }

        // Check minimum order amount.
        if ( $discount->minimum_order_amount && $cart_total < $discount->minimum_order_amount ) {
            return array(
                'valid' => false,
                'error' => sprintf(
                    /* translators: %s: minimum order amount */
                    __( 'Minimum order amount of %s required for this discount.', 'ggm-commerce' ),
                    GGM_Commerce_Helpers::format_price( $discount->minimum_order_amount )
                ),
            );
        }

        // Check voucher balance.
        if ( self::TYPE_VOUCHER === $discount->discount_type ) {
            if ( $discount->current_balance <= 0 ) {
                return array(
                    'valid' => false,
                    'error' => __( 'This voucher has no remaining balance.', 'ggm-commerce' ),
                );
            }
        }

        // Calculate discount amount.
        $discount_amount = $this->calculate_discount_amount( $discount, $cart_total, $cart_items );

        return array(
            'valid'           => true,
            'discount'        => $discount,
            'discount_amount' => $discount_amount,
            'message'         => sprintf(
                /* translators: %s: discount amount */
                __( 'Discount of %s applied!', 'ggm-commerce' ),
                GGM_Commerce_Helpers::format_price( $discount_amount )
            ),
        );
    }

    /**
     * Calculate discount amount
     *
     * @param object $discount   Discount object.
     * @param float  $cart_total Cart total.
     * @param array  $cart_items Optional cart items.
     * @return float Discount amount.
     */
    public function calculate_discount_amount( $discount, $cart_total, $cart_items = array() ) {
        $discount_amount = 0.00;

        switch ( $discount->discount_type ) {
            case self::TYPE_PERCENTAGE:
                $discount_amount = $cart_total * ( $discount->amount / 100 );
                break;

            case self::TYPE_FIXED:
                $discount_amount = $discount->amount;
                break;

            case self::TYPE_VOUCHER:
                if ( $discount->single_use_voucher ) {
                    // Use entire balance.
                    $discount_amount = min( $discount->current_balance, $cart_total );
                } else {
                    // Use only what's needed.
                    $discount_amount = min( $discount->current_balance, $cart_total );
                }
                break;
        }

        // Apply maximum discount cap.
        if ( $discount->maximum_discount_amount && $discount_amount > $discount->maximum_discount_amount ) {
            $discount_amount = $discount->maximum_discount_amount;
        }

        // Don't exceed cart total.
        if ( $discount_amount > $cart_total ) {
            $discount_amount = $cart_total;
        }

        return round( $discount_amount, 2 );
    }

    /**
     * Apply discount to cart session
     *
     * @param string $code       Discount code.
     * @param string $session_id Session ID.
     * @return array Result.
     */
    public function apply_discount_to_cart( $code, $session_id ) {
        // Store in session.
        if ( ! isset( $_SESSION ) ) {
            if ( session_status() === PHP_SESSION_NONE ) {
                session_start();
            }
        }

        $_SESSION['ggmc_discount_code'] = strtoupper( sanitize_text_field( $code ) );

        return array(
            'success' => true,
            'message' => __( 'Discount applied successfully.', 'ggm-commerce' ),
        );
    }

    /**
     * Remove discount from cart session
     *
     * @param string $session_id Session ID.
     * @return array Result.
     */
    public function remove_discount_from_cart( $session_id ) {
        if ( ! isset( $_SESSION ) ) {
            if ( session_status() === PHP_SESSION_NONE ) {
                session_start();
            }
        }

        unset( $_SESSION['ggmc_discount_code'] );

        return array(
            'success' => true,
            'message' => __( 'Discount removed.', 'ggm-commerce' ),
        );
    }

    /**
     * Get applied discount from session
     *
     * @return object|null Discount object or null.
     */
    public function get_applied_discount() {
        if ( ! isset( $_SESSION ) ) {
            if ( session_status() === PHP_SESSION_NONE ) {
                session_start();
            }
        }

        if ( empty( $_SESSION['ggmc_discount_code'] ) ) {
            return null;
        }

        return $this->get_discount_by_code( $_SESSION['ggmc_discount_code'] );
    }

    /**
     * Get voucher balance
     *
     * @param string $code Voucher code.
     * @return array Balance info.
     */
    public function get_voucher_balance( $code ) {
        $discount = $this->get_discount_by_code( $code );

        if ( ! $discount || self::TYPE_VOUCHER !== $discount->discount_type ) {
            return array(
                'success' => false,
                'error'   => __( 'Invalid voucher code.', 'ggm-commerce' ),
            );
        }

        return array(
            'success'         => true,
            'code'            => $discount->code,
            'initial_value'   => (float) $discount->initial_value,
            'current_balance' => (float) $discount->current_balance,
        );
    }

    /**
     * Deduct voucher balance
     *
     * @param string $code   Voucher code.
     * @param float  $amount Amount to deduct.
     * @return array Result.
     */
    public function deduct_voucher_balance( $code, $amount ) {
        global $wpdb;

        $discount = $this->get_discount_by_code( $code );

        if ( ! $discount || self::TYPE_VOUCHER !== $discount->discount_type ) {
            return array(
                'success' => false,
                'error'   => __( 'Invalid voucher code.', 'ggm-commerce' ),
            );
        }

        $new_balance = max( 0, $discount->current_balance - $amount );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->update(
            "{$wpdb->prefix}ggmc_discounts",
            array( 'current_balance' => $new_balance ),
            array( 'id' => $discount->id ),
            array( '%f' ),
            array( '%d' )
        );

        return array(
            'success'        => true,
            'previous_balance' => $discount->current_balance,
            'amount_deducted' => $amount,
            'new_balance'    => $new_balance,
        );
    }

    /**
     * Bulk generate vouchers
     *
     * @param int    $count  Number of vouchers to generate.
     * @param float  $value  Value per voucher.
     * @param string $prefix Code prefix.
     * @param array  $options Additional options.
     * @return array Result with generated codes.
     */
    public function bulk_generate_vouchers( $count, $value, $prefix = 'GIFT', $options = array() ) {
        $count = min( absint( $count ), 1000 ); // Limit to 1000.
        $value = floatval( $value );
        $prefix = strtoupper( sanitize_text_field( $prefix ) );

        if ( $count < 1 || $value <= 0 ) {
            return array(
                'success' => false,
                'error'   => __( 'Invalid count or value.', 'ggm-commerce' ),
            );
        }

        $generated = array();
        $failed = 0;

        for ( $i = 0; $i < $count; $i++ ) {
            $code = $prefix . '-' . strtoupper( wp_generate_password( 8, false ) );

            $data = array_merge(
                array(
                    'code'          => $code,
                'name'          => sprintf(
                        /* translators: %s: voucher code */
                        __( 'Gift Voucher %s', 'ggm-commerce' ),
                        $code
                    ),
                    'discount_type' => self::TYPE_VOUCHER,
                    'amount'        => $value,
                    'single_use_voucher' => isset( $options['single_use'] ) ? $options['single_use'] : 0,
                    'valid_to'      => isset( $options['expiry_date'] ) ? $options['expiry_date'] : null,
                    'status'        => 'active',
                ),
                $options
            );

            $result = $this->create_discount( $data );

            if ( $result['success'] ) {
                $generated[] = $code;
            } else {
                $failed++;
            }
        }

        return array(
            'success'   => true,
            'generated' => $generated,
            'count'     => count( $generated ),
            'failed'    => $failed,
            'message'   => sprintf(
                /* translators: %d: number of vouchers generated */
                __( 'Successfully generated %d vouchers.', 'ggm-commerce' ),
                count( $generated )
            ),
        );
    }

    /**
     * Process gift card order items and generate vouchers.
     *
     * @param int $order_id Order ID.
     */
    public function process_gift_card_order_items( $order_id ) {
        global $wpdb;

        // Get order items.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $order_items = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT oi.*, p.product_type, p.gift_card_value, p.gift_card_type, p.gift_card_single_use,
                        p.gift_card_valid_days, p.gift_card_code_prefix, p.name as product_name, p.price as product_price
                 FROM {$wpdb->prefix}ggmc_order_items oi
                 JOIN {$wpdb->prefix}ggmc_products p ON oi.product_id = p.id
                 WHERE oi.order_id = %d AND p.product_type = 'gift_card' AND (oi.generated_voucher_id IS NULL OR oi.generated_voucher_id = 0)",
                $order_id
            )
        );

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

        // Get order details for recipient email.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $order = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_orders WHERE id = %d",
                $order_id
            )
        );

        if ( ! $order ) {
            return;
        }

        foreach ( $order_items as $item ) {
            // Generate vouchers for each quantity.
            for ( $i = 0; $i < $item->quantity; $i++ ) {
                $voucher_result = $this->generate_gift_card_voucher( $item, $order );

                if ( $voucher_result['success'] && $i === 0 ) {
                    // Update order item with first voucher info (for reference).
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                    $wpdb->update(
                        "{$wpdb->prefix}ggmc_order_items",
                        array(
                            'generated_voucher_id'   => $voucher_result['discount_id'],
                            'generated_voucher_code' => $voucher_result['code'],
                            'voucher_recipient_email' => $order->customer_email,
                        ),
                        array( 'id' => $item->id ),
                        array( '%d', '%s', '%s' ),
                        array( '%d' )
                    );
                }

                // Send email for each voucher.
                if ( $voucher_result['success'] ) {
                    $this->send_voucher_email( $voucher_result, $order, $item );
                }
            }
        }
    }

    /**
     * Generate a single voucher from a gift card product purchase.
     *
     * @param object $item  Order item with product data.
     * @param object $order Order object.
     * @return array Result with voucher details.
     */
    public function generate_gift_card_voucher( $item, $order ) {
        // Determine voucher value (use gift_card_value if set, otherwise use product price).
        $voucher_value = ! empty( $item->gift_card_value ) ? floatval( $item->gift_card_value ) : floatval( $item->product_price );

        // Determine voucher type.
        $discount_type = ( $item->gift_card_type === 'percentage' ) ? self::TYPE_PERCENTAGE : self::TYPE_VOUCHER;

        // Generate unique code.
        $prefix = ! empty( $item->gift_card_code_prefix ) ? strtoupper( $item->gift_card_code_prefix ) : 'GC';
        $code = $prefix . '-' . strtoupper( wp_generate_password( 8, false ) );

        // Calculate expiry date.
        $valid_to = null;
        if ( ! empty( $item->gift_card_valid_days ) && intval( $item->gift_card_valid_days ) > 0 ) {
            $valid_to = gmdate( 'Y-m-d H:i:s', strtotime( '+' . intval( $item->gift_card_valid_days ) . ' days' ) );
        }

        // Create the voucher/discount.
        $data = array(
            'code'             => $code,
            'name'             => sprintf(
                /* translators: 1: product name, 2: order number */
                __( 'Gift Card: %1$s (Order #%2$s)', 'ggm-commerce' ),
                $item->product_name,
                $order->order_number
            ),
            'description'      => sprintf(
                /* translators: 1: order number, 2: order date */
                __( 'Auto-generated gift card voucher from order #%1$s on %2$s', 'ggm-commerce' ),
                $order->order_number,
                wp_date( get_option( 'date_format' ), strtotime( $order->created_at ) )
            ),
            'discount_type'    => $discount_type,
            'amount'           => $voucher_value,
            'initial_value'    => ( $discount_type === self::TYPE_VOUCHER ) ? $voucher_value : null,
            'current_balance'  => ( $discount_type === self::TYPE_VOUCHER ) ? $voucher_value : null,
            'single_use_voucher' => ! empty( $item->gift_card_single_use ) ? 1 : 0,
            'usage_limit'      => ( ! empty( $item->gift_card_single_use ) ) ? 1 : null,
            'valid_to'         => $valid_to,
            'status'           => 'active',
            'created_by'       => 0, // System generated.
        );

        $result = $this->create_discount( $data );

        if ( $result['success'] ) {
            $result['code'] = $code;
            $result['value'] = $voucher_value;
            $result['type'] = $discount_type;
            $result['expires'] = $valid_to;
        }

        return $result;
    }

    /**
     * Send voucher email to recipient.
     *
     * @param array  $voucher Voucher data.
     * @param object $order   Order object.
     * @param object $item    Order item.
     */
    public function send_voucher_email( $voucher, $order, $item ) {
        if ( ! class_exists( 'GGM_Commerce_Email_Manager' ) ) {
            return;
        }

        $email_manager = GGM_Commerce_Email_Manager::instance();

        // Prepare voucher data for email.
        $voucher_data = array(
            'code'         => $voucher['code'],
            'value'        => $voucher['value'],
            'type'         => $voucher['type'],
            'expires'      => $voucher['expires'],
            'product_name' => $item->product_name,
            'order_number' => $order->order_number,
            'recipient'    => $order->customer_email,
        );

        // Send the voucher email.
        $email_manager->send_voucher_email( $order->customer_email, $voucher_data, $order );
    }

    /**
     * Record discount usage
     *
     * @param int    $discount_id   Discount ID.
     * @param int    $order_id      Order ID.
     * @param float  $amount        Discount amount used.
     * @param array  $customer_data Customer data.
     * @return array Result.
     */
    public function record_usage( $discount_id, $order_id, $amount, $customer_data ) {
        global $wpdb;

        $discount = $this->get_discount( $discount_id );
        if ( ! $discount ) {
            return array(
                'success' => false,
                'error'   => __( 'Discount not found.', 'ggm-commerce' ),
            );
        }

        $insert_data = array(
            'discount_id'     => $discount_id,
            'order_id'        => $order_id,
            'customer_id'     => isset( $customer_data['customer_id'] ) ? absint( $customer_data['customer_id'] ) : null,
            'customer_email'  => isset( $customer_data['email'] ) ? sanitize_email( $customer_data['email'] ) : '',
            'discount_amount' => $amount,
        );

        // Track voucher balance changes.
        if ( self::TYPE_VOUCHER === $discount->discount_type ) {
            $insert_data['voucher_balance_before'] = $discount->current_balance;
            $new_balance = max( 0, $discount->current_balance - $amount );
            $insert_data['voucher_balance_after'] = $new_balance;

            // Update voucher balance.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                "{$wpdb->prefix}ggmc_discounts",
                array( 'current_balance' => $new_balance ),
                array( 'id' => $discount_id ),
                array( '%f' ),
                array( '%d' )
            );
        }

        // Insert usage record.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->insert(
            "{$wpdb->prefix}ggmc_discount_usage",
            $insert_data
        );

        // Increment usage count.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->query(
            $wpdb->prepare(
                "UPDATE {$wpdb->prefix}ggmc_discounts SET usage_count = usage_count + 1 WHERE id = %d",
                $discount_id
            )
        );

        return array(
            'success'  => true,
            'usage_id' => $wpdb->insert_id,
        );
    }

    /**
     * Get usage history for a discount
     *
     * @param int $discount_id Discount ID.
     * @param int $limit       Max records to return.
     * @return array Usage records.
     */
    public function get_usage_history( $discount_id, $limit = 50 ) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_discount_usage
                 WHERE discount_id = %d
                 ORDER BY used_at DESC
                 LIMIT %d",
                $discount_id,
                $limit
            )
        );
    }

    /**
     * Get customer usage count for a discount
     *
     * @param int    $discount_id    Discount ID.
     * @param string $customer_email Customer email.
     * @return int Usage count.
     */
    public function get_customer_usage( $discount_id, $customer_email ) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_discount_usage
                 WHERE discount_id = %d AND customer_email = %s",
                $discount_id,
                $customer_email
            )
        );
    }

    /**
     * AJAX: Validate discount code
     */
    public function ajax_validate_discount() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_nonce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $code = isset( $_POST['code'] ) ? sanitize_text_field( wp_unslash( $_POST['code'] ) ) : '';
        $cart_total = isset( $_POST['cart_total'] ) ? floatval( $_POST['cart_total'] ) : 0;
        $customer_email = isset( $_POST['customer_email'] ) ? sanitize_email( wp_unslash( $_POST['customer_email'] ) ) : '';

        $result = $this->validate_discount_code( $code, $cart_total, $customer_email );

        if ( $result['valid'] ) {
            wp_send_json_success(
                array(
                    'valid'           => true,
                    'discount_amount' => $result['discount_amount'],
                    'message'         => $result['message'],
                    'discount_type'   => $result['discount']->discount_type,
                )
            );
        } else {
            wp_send_json_error(
                array(
                    'valid'   => false,
                    'message' => $result['error'],
                )
            );
        }
    }

    /**
     * AJAX: Apply discount to cart
     */
    public function ajax_apply_discount() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_nonce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $code = isset( $_POST['code'] ) ? sanitize_text_field( wp_unslash( $_POST['code'] ) ) : '';
        $cart_total = isset( $_POST['cart_total'] ) ? floatval( $_POST['cart_total'] ) : 0;
        $customer_email = isset( $_POST['customer_email'] ) ? sanitize_email( wp_unslash( $_POST['customer_email'] ) ) : '';

        // Validate first.
        $validation = $this->validate_discount_code( $code, $cart_total, $customer_email );

        if ( ! $validation['valid'] ) {
            wp_send_json_error( array( 'message' => $validation['error'] ) );
        }

        // Apply to session.
        $result = $this->apply_discount_to_cart( $code, session_id() );

        wp_send_json_success(
            array(
                'message'         => $validation['message'],
                'discount_amount' => $validation['discount_amount'],
                'discount_type'   => $validation['discount']->discount_type,
                'discount_code'   => $validation['discount']->code,
            )
        );
    }

    /**
     * AJAX: Remove discount from cart
     */
    public function ajax_remove_discount() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_nonce' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $result = $this->remove_discount_from_cart( session_id() );

        wp_send_json_success( $result );
    }

    /**
     * AJAX: Create discount (admin)
     */
    public function ajax_create_discount() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_admin' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permission denied.', 'ggm-commerce' ) ) );
        }

        $data = isset( $_POST['discount'] ) ? wp_unslash( $_POST['discount'] ) : array();
        $result = $this->create_discount( $data );

        if ( $result['success'] ) {
            wp_send_json_success( $result );
        } else {
            wp_send_json_error( $result );
        }
    }

    /**
     * AJAX: Update discount (admin)
     */
    public function ajax_update_discount() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_admin' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permission denied.', 'ggm-commerce' ) ) );
        }

        $id = isset( $_POST['discount_id'] ) ? absint( $_POST['discount_id'] ) : 0;
        $data = isset( $_POST['discount'] ) ? wp_unslash( $_POST['discount'] ) : array();

        $result = $this->update_discount( $id, $data );

        if ( $result['success'] ) {
            wp_send_json_success( $result );
        } else {
            wp_send_json_error( $result );
        }
    }

    /**
     * AJAX: Delete discount (admin)
     */
    public function ajax_delete_discount() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_admin' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permission denied.', 'ggm-commerce' ) ) );
        }

        $id = isset( $_POST['discount_id'] ) ? absint( $_POST['discount_id'] ) : 0;

        $result = $this->delete_discount( $id );

        if ( $result['success'] ) {
            wp_send_json_success( $result );
        } else {
            wp_send_json_error( $result );
        }
    }

    /**
     * AJAX: Get discount (admin)
     */
    public function ajax_get_discount() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_admin' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permission denied.', 'ggm-commerce' ) ) );
        }

        $id = isset( $_POST['discount_id'] ) ? absint( $_POST['discount_id'] ) : 0;
        $discount = $this->get_discount( $id );

        if ( $discount ) {
            wp_send_json_success( $discount );
        } else {
            wp_send_json_error( array( 'message' => __( 'Discount not found.', 'ggm-commerce' ) ) );
        }
    }

    /**
     * AJAX: Bulk generate vouchers (admin)
     */
    public function ajax_bulk_generate_vouchers() {
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification.
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ggmc_discount_admin' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permission denied.', 'ggm-commerce' ) ) );
        }

        $count = isset( $_POST['count'] ) ? absint( $_POST['count'] ) : 0;
        $value = isset( $_POST['value'] ) ? floatval( $_POST['value'] ) : 0;
        $prefix = isset( $_POST['prefix'] ) ? sanitize_text_field( wp_unslash( $_POST['prefix'] ) ) : 'GIFT';
        $options = array(
            'single_use'  => isset( $_POST['single_use'] ) ? absint( $_POST['single_use'] ) : 0,
            'expiry_date' => isset( $_POST['expiry_date'] ) && ! empty( $_POST['expiry_date'] ) ? sanitize_text_field( wp_unslash( $_POST['expiry_date'] ) ) : null,
        );

        $result = $this->bulk_generate_vouchers( $count, $value, $prefix, $options );

        if ( $result['success'] ) {
            wp_send_json_success( $result );
        } else {
            wp_send_json_error( $result );
        }
    }
}
