<?php
/**
 * WooCommerce Service
 *
 * Provides access to WooCommerce data for the chatbot.
 *
 * @package BoostBot
 * @since 1.0.0
 */

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

/**
 * Class BoostBot_WooCommerce_Service
 *
 * Handles all WooCommerce interactions.
 */
class BoostBot_WooCommerce_Service {

    /**
     * Check if WooCommerce is active.
     *
     * @return bool
     */
    public static function is_active(): bool {
        return class_exists( 'WooCommerce' );
    }

    /**
     * Search products by query.
     *
     * @param string $query   Search query.
     * @param array  $options Search options.
     * @return array Products array.
     */
    public function search_products( string $query, array $options = array() ): array {
        if ( ! self::is_active() ) {
            return array();
        }

        $args = array(
            's'              => $query,
            'post_type'      => 'product',
            'post_status'    => 'publish',
            'posts_per_page' => $options['limit'] ?? 5,
        );

        if ( ! empty( $options['lang'] ) ) {
            $args['lang'] = $options['lang'];
        }

        // Category filter
        if ( ! empty( $options['category'] ) ) {
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- standard WooCommerce category filtering
            $args['tax_query'] = array(
                array(
                    'taxonomy' => 'product_cat',
                    'field'    => 'slug',
                    'terms'    => $options['category'],
                ),
            );
        }

        // Price range filter
        if ( isset( $options['min_price'] ) || isset( $options['max_price'] ) ) {
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- standard WooCommerce price filtering
            $args['meta_query'] = array(
                array(
                    'key'     => '_price',
                    'value'   => array(
                        $options['min_price'] ?? 0,
                        $options['max_price'] ?? 999999,
                    ),
                    'type'    => 'NUMERIC',
                    'compare' => 'BETWEEN',
                ),
            );
        }

        // Sorting
        if ( ! empty( $options['orderby'] ) ) {
            switch ( $options['orderby'] ) {
                case 'price':
                    $args['meta_key'] = '_price'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- WooCommerce sort by price
                    $args['orderby']  = 'meta_value_num';
                    $args['order']    = $options['order'] ?? 'ASC';
                    break;
                case 'popularity':
                    $args['meta_key'] = 'total_sales'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- WooCommerce sort by sales
                    $args['orderby']  = 'meta_value_num';
                    $args['order']    = 'DESC';
                    break;
                case 'rating':
                    $args['meta_key'] = '_wc_average_rating'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- WooCommerce sort by rating
                    $args['orderby']  = 'meta_value_num';
                    $args['order']    = 'DESC';
                    break;
                default:
                    $args['orderby'] = $options['orderby'];
                    $args['order']   = $options['order'] ?? 'DESC';
            }
        }

        $products = get_posts( $args );

        return array_filter( array_map( array( $this, 'format_product' ), wp_list_pluck( $products, 'ID' ) ) );
    }

    /**
     * Get a single product by ID.
     *
     * @param int $product_id Product ID.
     * @return array|null Product data or null.
     */
    public function get_product( int $product_id ): ?array {
        if ( ! self::is_active() ) {
            return null;
        }

        return $this->format_product( $product_id );
    }

    /**
     * Get products by category.
     *
     * @param string      $category_slug Category slug.
     * @param int         $limit         Number of products.
     * @param string|null $language      Language code.
     * @return array Products array.
     */
    public function get_products_by_category( string $category_slug, int $limit = 10, ?string $language = null ): array {
        if ( ! self::is_active() ) {
            return array();
        }

        $args = array(
            'category' => array( $category_slug ),
            'limit'    => $limit,
            'status'   => 'publish',
        );

        if ( $language ) {
            $args['lang'] = $language;
        }

        $products = wc_get_products( $args );

        return array_filter( array_map( fn( $p ) => $this->format_product( $p->get_id() ), $products ) );
    }

    /**
     * Get featured products.
     *
     * @param int $limit Number of products.
     * @return array Products array.
     */
    public function get_featured_products( int $limit = 5, ?string $language = null ): array {
        if ( ! self::is_active() ) {
            return array();
        }

        $args = array(
            'featured' => true,
            'limit'    => $limit,
            'status'   => 'publish',
        );
        if ( $language ) {
            $args['lang'] = $language;
        }

        $products = wc_get_products( $args );

        return array_filter( array_map( fn( $p ) => $this->format_product( $p->get_id() ), $products ) );
    }

    /**
     * Get on-sale products.
     *
     * @param int         $limit    Number of products.
     * @param string|null $language Language code.
     * @return array Products array.
     */
    public function get_on_sale_products( int $limit = 5, ?string $language = null ): array {
        if ( ! self::is_active() ) {
            return array();
        }

        $args = array(
            'limit'    => $limit,
            'status'   => 'publish',
            'on_sale'  => true,
        );

        if ( $language ) {
            $args['lang'] = $language;
        }

        // If wc_get_products doesn't support 'lang' directly for on_sale (some WC versions),
        // we fallback to a manual ID filter if we have a language.
        if ( $language && function_exists( 'pll_get_post' ) ) {
            $product_ids = wc_get_product_ids_on_sale();
            $filtered_ids = array();
            foreach ( $product_ids as $id ) {
                $lang_id = pll_get_post( $id, $language );
                if ( $lang_id && ! in_array( $lang_id, $filtered_ids, true ) ) {
                    $filtered_ids[] = $lang_id;
                }
                if ( count( $filtered_ids ) >= $limit ) {
                    break;
                }
            }
            if ( ! empty( $filtered_ids ) ) {
                $args['include'] = $filtered_ids;
                unset( $args['on_sale'] ); // Use explicit IDs
            }
        }

        $products = wc_get_products( $args );

        return array_filter( array_map( fn( $p ) => $this->format_product( $p->get_id() ), $products ) );
    }

    /**
     * Get best-selling products.
     *
     * @param int         $limit    Number of products.
     * @param string|null $language Language code.
     * @return array Products array.
     */
    public function get_best_sellers( int $limit = 5, ?string $language = null ): array {
        if ( ! self::is_active() ) {
            return array();
        }

        $args = array(
            'limit'    => $limit,
            'status'   => 'publish',
            'orderby'  => 'meta_value_num',
            'meta_key' => 'total_sales', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- WooCommerce best-sellers sort
            'order'    => 'DESC',
        );

        if ( $language ) {
            $args['lang'] = $language;
        }

        $products = wc_get_products( $args );

        return array_filter( array_map( fn( $p ) => $this->format_product( $p->get_id() ), $products ) );
    }

    /**
     * Get related products.
     *
     * @param int         $product_id Product ID.
     * @param int         $limit      Number of products.
     * @param string|null $language   Language code.
     * @return array Products array.
     */
    public function get_related_products( int $product_id, int $limit = 4, ?string $language = null ): array {
        if ( ! self::is_active() ) {
            return array();
        }

        $fetch_limit = $language && function_exists( 'pll_get_post' ) ? $limit * 3 : $limit;
        $related_ids = wc_get_related_products( $product_id, $fetch_limit );

        if ( $language && function_exists( 'pll_get_post' ) ) {
            $related_ids = array_map( fn( $id ) => pll_get_post( $id, $language ), $related_ids );
            $related_ids = array_filter( $related_ids );
        }

        $related_ids = array_slice( $related_ids, 0, $limit );

        return array_filter( array_map( array( $this, 'format_product' ), $related_ids ) );
    }

    /**
     * Format product data for API response.
     *
     * @param int $product_id Product ID.
     * @return array|null Formatted product or null.
     */
    private function format_product( int $product_id ): ?array {
        $product = wc_get_product( $product_id );

        if ( ! $product ) {
            return null;
        }

        // Override WooCommerce currency for this product's language so that
        // get_price_html() and get_woocommerce_currency_symbol() return correct values.
        $product_lang = function_exists( 'pll_get_post_language' )
            ? pll_get_post_language( $product_id )
            : '';
        $currency_override = $product_lang
            ? BoostBot_Polylang_Context::override_currency_for_language( $product_lang )
            : null;
        $currency_snapshot = BoostBot_Polylang_Context::get_currency_for_language( $product_lang ?: $this->resolve_language() );

        $image_id  = $product->get_image_id();
        $image_url = $image_id ? wp_get_attachment_image_url( $image_id, 'medium' ) : wc_placeholder_img_src( 'medium' );
        $sale_percentage = $this->calculate_sale_percentage( $product );
        $max_purchase_quantity = (int) $product->get_max_purchase_quantity();

        $data = array(
            'id'                => $product_id,
            'name'              => $product->get_name(),
            'slug'              => $product->get_slug(),
            'price'             => $product->get_price(),
            'regular_price'     => $product->get_regular_price(),
            'sale_price'        => $product->get_sale_price(),
            'formatted_price'   => wp_strip_all_tags( $product->get_price_html() ),
            'formatted_regular_price' => $product->get_regular_price() !== ''
                ? $this->format_price_display( $product->get_regular_price() )
                : '',
            'formatted_sale_price' => $product->get_sale_price() !== ''
                ? $this->format_price_display( $product->get_sale_price() )
                : '',
            'currency'          => $currency_snapshot['symbol'],
            'currency_code'     => $currency_snapshot['code'],
            'url'               => urldecode( $product->get_permalink() ),
            'image'             => $image_url,
            'short_description' => wp_trim_words( wp_strip_all_tags( $product->get_short_description() ), 20 ),
            'description'       => wp_trim_words( wp_strip_all_tags( $product->get_description() ), 50 ),
            'categories'        => wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'names' ) ),
            'stock_status'      => $product->get_stock_status(),
            'stock_quantity'    => $product->get_stock_quantity(),
            'in_stock'          => $product->is_in_stock(),
            'on_sale'           => $product->is_on_sale(),
            'is_on_sale'        => $product->is_on_sale(),
            'sale_percentage'   => $sale_percentage,
            'is_purchasable'    => $product->is_purchasable(),
            'max_quantity'      => $max_purchase_quantity > 0 ? $max_purchase_quantity : null,
            'average_rating'    => floatval( $product->get_average_rating() ),
            'review_count'      => $product->get_review_count(),
            'product_type'      => $product->get_type(),
            'type'              => $product->get_type(),
            'variations'        => $this->build_variation_summary( $product ),
            'sku'               => $product->get_sku(),
        );

        BoostBot_Polylang_Context::restore_currency( $currency_override );

        return $data;
    }

    /**
     * Add product to cart.
     *
     * @param int   $product_id   Product ID.
     * @param int   $quantity     Quantity.
     * @param int   $variation_id Variation ID.
     * @param array $variation    Variation attributes.
     * @param string $language    Optional language override for cart snapshot.
     * @return array Result with success status.
     */
    public function add_to_cart(
        int $product_id,
        int $quantity = 1,
        int $variation_id = 0,
        array $variation = array(),
        string $language = ''
    ): array {
        $resolved_language = $this->resolve_language( $language );
        $is_english        = 'en' === $resolved_language;

        if ( ! self::is_active() ) {
            return array(
                'success' => false,
                'message' => __( 'WooCommerce לא פעיל', 'boostbot' ),
            );
        }

        if ( ! $this->bootstrap_cart_context() ) {
            return array(
                'success' => false,
                'message' => __( 'Cart is unavailable right now', 'boostbot' ),
            );
        }

        $product = wc_get_product( $product_id );

        if ( ! $product ) {
            return array(
                'success' => false,
                'message' => __( 'מוצר לא נמצא', 'boostbot' ),
            );
        }

        $quantity = (int) $quantity;
        if ( $quantity <= 0 ) {
            return array(
                'success' => false,
                'message' => $is_english
                    ? __( 'Quantity must be at least 1', 'boostbot' )
                    : __( 'הכמות חייבת להיות לפחות 1', 'boostbot' ),
            );
        }

        $cart_product = $variation_id ? wc_get_product( $variation_id ) : $product;
        if ( ! $cart_product ) {
            return array(
                'success' => false,
                'message' => $is_english
                    ? __( 'Product option not found', 'boostbot' )
                    : __( 'אפשרות המוצר לא נמצאה', 'boostbot' ),
            );
        }

        if ( $product->is_type( 'variable' ) && $variation_id <= 0 ) {
            return array(
                'success' => false,
                'message' => $is_english
                    ? __( 'Please select a product option', 'boostbot' )
                    : __( 'נא לבחור אפשרות למוצר', 'boostbot' ),
            );
        }

        if ( ! $cart_product->is_purchasable() ) {
            return array(
                'success' => false,
                'message' => $is_english
                    ? __( 'This product cannot be purchased right now', 'boostbot' )
                    : __( 'לא ניתן לרכוש את המוצר הזה כרגע', 'boostbot' ),
            );
        }

        if ( ! $cart_product->is_in_stock() ) {
            return array(
                'success' => false,
                'message' => __( 'המוצר אזל מהמלאי', 'boostbot' ),
            );
        }

        $quantity      = max( 1, $quantity );
        $cart_item_id  = WC()->cart->generate_cart_id( $product_id, $variation_id, $variation );
        $existing_key  = WC()->cart->find_product_in_cart( $cart_item_id );
        $existing_qty  = $existing_key && isset( WC()->cart->cart_contents[ $existing_key ]['quantity'] )
            ? (int) WC()->cart->cart_contents[ $existing_key ]['quantity']
            : 0;
        $max_purchase_quantity = (int) $cart_product->get_max_purchase_quantity();

        if ( $max_purchase_quantity > 0 && ( $existing_qty + $quantity ) > $max_purchase_quantity ) {
            return array(
                'success' => false,
                'message' => $is_english
                    /* translators: %d: maximum purchasable quantity for this product */
                    ? sprintf( __( 'Only %d units are available right now', 'boostbot' ), $max_purchase_quantity )
                    /* translators: %d: maximum purchasable quantity for this product */
                    : sprintf( __( 'זמינות כרגע רק %d יחידות', 'boostbot' ), $max_purchase_quantity ),
            );
        }

        $cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );

        if ( $cart_item_key ) {
            WC()->cart->calculate_totals();

            return array(
                'success'        => true,
                'message'        => sprintf(
                    /* translators: %s: product name */
                    $is_english ? __( '%s added to cart!', 'boostbot' ) : __( '%s נוסף לסל', 'boostbot' ),
                    $product->get_name()
                ),
                'cart_item_key'  => $cart_item_key,
                'cart_count'     => WC()->cart->get_cart_contents_count(),
                'cart_total'     => WC()->cart->get_cart_total(),
                'checkout_url'   => $this->get_store_page_url( 'checkout', $resolved_language ),
                'cart_url'       => $this->get_store_page_url( 'cart', $resolved_language ),
                'cart'           => $this->get_cart_info( $language ),
            );
        }

        return array(
            'success' => false,
            'message' => __( 'שגיאה בהוספה לסל', 'boostbot' ),
        );
    }

    /**
     * Calculate sale percentage for a product.
     *
     * @since 1.7.0
     * @param WC_Product $product Product object.
     * @return int|null
     */
    private function calculate_sale_percentage( \WC_Product $product ): ?int {
        $regular_price = (float) $product->get_regular_price();
        $sale_price    = (float) $product->get_sale_price();

        if ( $regular_price <= 0 || $sale_price <= 0 || $sale_price >= $regular_price ) {
            return null;
        }

        return (int) round( ( ( $regular_price - $sale_price ) / $regular_price ) * 100 );
    }

    /**
     * Build a compact summary of available variations for the widget.
     *
     * @since 1.7.0
     * @param WC_Product $product Product object.
     * @return array|null
     */
    private function build_variation_summary( \WC_Product $product ): ?array {
        if ( ! $product->is_type( 'variable' ) || ! method_exists( $product, 'get_available_variations' ) ) {
            return null;
        }

        $available_variations = $product->get_available_variations();
        if ( empty( $available_variations ) ) {
            return null;
        }

        $variations = array();

        foreach ( $available_variations as $variation_data ) {
            $variation_id = isset( $variation_data['variation_id'] ) ? (int) $variation_data['variation_id'] : 0;
            if ( $variation_id <= 0 ) {
                continue;
            }

            $variation = wc_get_product( $variation_id );
            if ( ! $variation ) {
                continue;
            }

            $max_quantity = (int) $variation->get_max_purchase_quantity();
            $attributes   = array();
            foreach ( (array) $variation->get_attributes() as $attribute_key => $attribute_value ) {
                if ( '' === $attribute_value || null === $attribute_value ) {
                    continue;
                }
                $attributes[ sanitize_title( (string) $attribute_key ) ] = wc_clean( (string) $attribute_value );
            }

            $attribute_label = implode( ' / ', array_values( $attributes ) );

            $variations[] = array(
                'id'             => $variation_id,
                'name'           => $attribute_label ?: $variation->get_name(),
                'sku'            => $variation->get_sku(),
                'price'          => $variation->get_price(),
                'regular_price'  => $variation->get_regular_price(),
                'formatted_price' => $variation->get_price() !== ''
                    ? $this->format_price_display( $variation->get_price() )
                    : '',
                'in_stock'       => $variation->is_in_stock(),
                'stock_status'   => $variation->get_stock_status(),
                'stock_quantity' => $variation->get_stock_quantity(),
                'is_purchasable' => $variation->is_purchasable(),
                'max_quantity'   => $max_quantity > 0 ? $max_quantity : null,
                'attributes'     => $attributes,
            );
        }

        return empty( $variations ) ? null : array_values( $variations );
    }

    /**
     * Get cart information.
     *
     * @return array|null Cart info or null.
     */
    public function get_cart_info( string $language = '' ): ?array {
        if ( ! self::is_active() ) {
            return null;
        }

        if ( ! $this->bootstrap_cart_context() ) {
            return $this->get_empty_cart_snapshot( $language );
        }

        $resolved_language = $this->resolve_language( $language );
        $currency_override = BoostBot_Polylang_Context::override_currency_for_language( $resolved_language );
        $currency          = BoostBot_Polylang_Context::get_currency_for_language( $resolved_language );
        $items = array();

        foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
            $product = $cart_item['data'];
            if ( ! $product ) {
                continue;
            }

            $display_product = $product;
            if ( $resolved_language && function_exists( 'pll_get_post' ) ) {
                $translated_id = pll_get_post( (int) $cart_item['product_id'], $resolved_language );
                if ( $translated_id ) {
                    $translated_product = wc_get_product( $translated_id );
                    if ( $translated_product ) {
                        $display_product = $translated_product;
                    }
                }
            }

            $category_names = array();
            $product_categories = wp_get_post_terms( $cart_item['product_id'], 'product_cat', array( 'fields' => 'names' ) );
            if ( ! is_wp_error( $product_categories ) ) {
                $category_names = $product_categories;
            }

            $items[] = array(
                'key'              => $cart_item_key,
                'id'               => (int) $cart_item['product_id'],
                'variation_id'     => (int) ( $cart_item['variation_id'] ?? 0 ),
                'name'             => $display_product->get_name(),
                'quantity'         => (int) $cart_item['quantity'],
                'price'            => (string) $product->get_price(),
                'price_display'    => $this->format_price_display( wc_get_price_to_display( $product ) ),
                'subtotal'         => $this->format_price_display( $cart_item['line_subtotal'] ?? 0 ),
                'subtotal_display' => $this->format_price_display( $cart_item['line_total'] ?? 0 ),
                'image'            => wp_get_attachment_image_url( $display_product->get_image_id(), 'thumbnail' ),
                'product_url'      => $display_product->is_visible() ? $display_product->get_permalink() : '',
                'categories'       => $category_names,
            );
        }

        $discount_total  = $this->get_cart_discount_total_amount();
        $applied_coupons = array();

        foreach ( WC()->cart->get_applied_coupons() as $coupon_code ) {
            $normalized_code = wc_format_coupon_code( $coupon_code );
            $coupon_object   = new \WC_Coupon( $normalized_code );
            $coupon_discount = $this->get_coupon_discount_total_amount( $normalized_code );

            $applied_coupons[] = array(
                'code'                   => $normalized_code,
                'discount_total'         => wc_format_decimal( $coupon_discount, wc_get_price_decimals() ),
                'discount_total_display' => $this->format_price_display( $coupon_discount ),
                'free_shipping'          => $coupon_object->get_id() ? (bool) $coupon_object->get_free_shipping() : false,
            );
        }

        $snapshot = array(
            'count'                  => WC()->cart->get_cart_contents_count(),
            'subtotal'               => $this->format_price_display( WC()->cart->get_subtotal() ),
            'subtotal_amount'        => wc_format_decimal( WC()->cart->get_subtotal(), wc_get_price_decimals() ),
            'total'                  => $this->format_price_display( WC()->cart->get_total( 'edit' ) ),
            'total_amount'           => wc_format_decimal( WC()->cart->get_total( 'edit' ), wc_get_price_decimals() ),
            'discount_total'         => wc_format_decimal( $discount_total, wc_get_price_decimals() ),
            'discount_total_display' => $this->format_price_display( $discount_total ),
            'currency_code'          => $currency['code'],
            'currency_symbol'        => $currency['symbol'],
            'applied_coupons'        => $applied_coupons,
            'items'                  => $items,
            'checkout_url'           => $this->get_store_page_url( 'checkout', $resolved_language ),
            'cart_url'               => $this->get_store_page_url( 'cart', $resolved_language ),
            'is_empty'               => WC()->cart->is_empty(),
        );

        BoostBot_Polylang_Context::restore_currency( $currency_override );

        return $snapshot;
    }

    /**
     * Update the quantity for an existing cart item.
     *
     * @param string $cart_item_key Cart item key.
     * @param int    $quantity      Target quantity.
     * @param string $language      Optional language override.
     * @return array Result payload.
     */
    public function update_cart_item_quantity( string $cart_item_key, int $quantity, string $language = '' ): array {
        if ( ! self::is_active() ) {
            return array(
                'success' => false,
                'message' => __( 'WooCommerce לא פעיל', 'boostbot' ),
            );
        }

        if ( ! $this->bootstrap_cart_context() ) {
            return array(
                'success' => false,
                'message' => __( 'Cart is unavailable right now', 'boostbot' ),
            );
        }

        $cart_item = WC()->cart->get_cart_item( $cart_item_key );
        if ( ! $cart_item ) {
            return array(
                'success' => false,
                'message' => __( 'Cart item not found', 'boostbot' ),
            );
        }

        if ( $quantity <= 0 ) {
            return $this->remove_cart_item( $cart_item_key, $language );
        }

        $updated = WC()->cart->set_quantity( $cart_item_key, $quantity, true );
        if ( false === $updated ) {
            return array(
                'success' => false,
                'message' => __( 'Unable to update cart item quantity', 'boostbot' ),
            );
        }

        WC()->cart->calculate_totals();

        return array(
            'success' => true,
            'message' => __( 'Cart updated', 'boostbot' ),
            'cart'    => $this->get_cart_info( $language ),
        );
    }

    /**
     * Remove a cart item by key.
     *
     * @param string $cart_item_key Cart item key.
     * @param string $language      Optional language override.
     * @return array Result payload.
     */
    public function remove_cart_item( string $cart_item_key, string $language = '' ): array {
        if ( ! self::is_active() ) {
            return array(
                'success' => false,
                'message' => __( 'WooCommerce לא פעיל', 'boostbot' ),
            );
        }

        if ( ! $this->bootstrap_cart_context() ) {
            return array(
                'success' => false,
                'message' => __( 'Cart is unavailable right now', 'boostbot' ),
            );
        }

        $removed = WC()->cart->remove_cart_item( $cart_item_key );
        if ( ! $removed ) {
            return array(
                'success' => false,
                'message' => __( 'Unable to remove cart item', 'boostbot' ),
            );
        }

        WC()->cart->calculate_totals();

        return array(
            'success' => true,
            'message' => __( 'Item removed from cart', 'boostbot' ),
            'cart'    => $this->get_cart_info( $language ),
        );
    }

    /**
     * Apply a coupon to the current cart session.
     *
     * @param string $code     Coupon code.
     * @param string $language Optional language override.
     * @return array
     */
    public function apply_coupon_to_cart( string $code, string $language = '' ): array {
        if ( ! self::is_active() ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'woo_inactive', $language ),
            );
        }

        if ( ! $this->bootstrap_cart_context() ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'cart_unavailable', $language ),
            );
        }

        $code = wc_format_coupon_code( wp_unslash( $code ) );
        if ( '' === $code ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'coupon_missing', $language ),
            );
        }

        $applied_codes = array_map( 'wc_format_coupon_code', WC()->cart->get_applied_coupons() );
        if ( in_array( $code, $applied_codes, true ) ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'coupon_already_applied', $language ),
                'cart'    => $this->get_cart_info( $language ),
            );
        }

        $coupon = new \WC_Coupon( $code );
        if ( ! $coupon->get_id() ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'coupon_invalid', $language ),
            );
        }

        $validation = $this->get_coupon_applicability_data( $coupon, $language );
        if ( empty( $validation['applicable'] ) ) {
            return array(
                'success' => false,
                'reason'  => $validation['reason'] ?: $this->get_localized_coupon_message( 'coupon_not_eligible', $language ),
                'cart'    => $this->get_cart_info( $language ),
            );
        }

        $before_discount = $this->get_cart_discount_total_amount();
        $applied         = WC()->cart->apply_coupon( $coupon->get_code() );
        WC()->cart->calculate_totals();

        if ( ! $applied ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'coupon_apply_failed', $language ),
                'cart'    => $this->get_cart_info( $language ),
            );
        }

        $after_discount = $this->get_cart_discount_total_amount();
        $delta          = max( 0, $after_discount - $before_discount );

        return array(
            'success'          => true,
            'message'          => $this->get_localized_coupon_message(
                'coupon_applied',
                $language,
                array( 'code' => $coupon->get_code() )
            ),
            'discount'         => wc_format_decimal( $delta, wc_get_price_decimals() ),
            'discount_display' => $this->format_price_for_language( $delta, $language ),
            'cart'             => $this->get_cart_info( $language ),
        );
    }

    /**
     * Remove a coupon from the current cart session.
     *
     * @param string $code     Coupon code.
     * @param string $language Optional language override.
     * @return array
     */
    public function remove_coupon_from_cart( string $code, string $language = '' ): array {
        if ( ! self::is_active() ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'woo_inactive', $language ),
            );
        }

        if ( ! $this->bootstrap_cart_context() ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'cart_unavailable', $language ),
            );
        }

        $code = wc_format_coupon_code( wp_unslash( $code ) );
        if ( '' === $code ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'coupon_missing', $language ),
            );
        }

        $applied_codes = array_map( 'wc_format_coupon_code', WC()->cart->get_applied_coupons() );
        if ( ! in_array( $code, $applied_codes, true ) ) {
            return array(
                'success' => false,
                'reason'  => $this->get_localized_coupon_message( 'coupon_not_applied', $language ),
                'cart'    => $this->get_cart_info( $language ),
            );
        }

        WC()->cart->remove_coupon( $code );
        WC()->cart->calculate_totals();

        return array(
            'success' => true,
            'message' => $this->get_localized_coupon_message(
                'coupon_removed',
                $language,
                array( 'code' => $code )
            ),
            'cart'    => $this->get_cart_info( $language ),
        );
    }

    /**
     * Build coupon applicability data for the current cart.
     *
     * @param WC_Coupon|int|string $coupon   Coupon object, ID, or code.
     * @param string               $language Optional language override.
     * @return array
     */
    public function get_coupon_applicability_data( $coupon, string $language = '' ): array {
        $resolved_coupon = $coupon instanceof \WC_Coupon ? $coupon : new \WC_Coupon( $coupon );
        $resolved_code   = $resolved_coupon->get_code();
        $resolved_lang   = $this->resolve_language( $language );

        $result = array(
            'applicable'            => false,
            'reason'                => null,
            'reason_code'           => null,
            'min_spend'             => null,
            'min_spend_display'     => null,
            'max_spend'             => null,
            'max_spend_display'     => null,
            'spend_gap'             => null,
            'spend_gap_display'     => null,
            'eligible_products'     => null,
            'eligible_categories'   => null,
            'expiry_date'           => null,
            'usage_remaining'       => null,
            'is_applied'            => false,
            'free_shipping'         => false,
            'expires_soon'          => false,
        );

        if ( ! self::is_active() || ! $resolved_coupon->get_id() ) {
            $result['reason']      = $this->get_localized_coupon_message( 'coupon_invalid', $resolved_lang );
            $result['reason_code'] = 'invalid_coupon';
            return $result;
        }

        if ( ! $this->bootstrap_cart_context() ) {
            $result['reason']      = $this->get_localized_coupon_message( 'cart_unavailable', $resolved_lang );
            $result['reason_code'] = 'cart_unavailable';
            return $result;
        }

        $min_spend = $resolved_coupon->get_minimum_amount();
        $max_spend = $resolved_coupon->get_maximum_amount();
        $expiry    = $resolved_coupon->get_date_expires();

        $result['min_spend']           = '' !== $min_spend ? (float) $min_spend : null;
        $result['min_spend_display']   = null !== $result['min_spend'] ? $this->format_price_for_language( $result['min_spend'], $resolved_lang ) : null;
        $result['max_spend']           = '' !== $max_spend ? (float) $max_spend : null;
        $result['max_spend_display']   = null !== $result['max_spend'] ? $this->format_price_for_language( $result['max_spend'], $resolved_lang ) : null;
        $result['free_shipping']       = (bool) $resolved_coupon->get_free_shipping();
        $result['eligible_products']   = $this->get_coupon_product_names( $resolved_coupon, $resolved_lang );
        $result['eligible_categories'] = $this->get_coupon_category_names( $resolved_coupon, $resolved_lang );
        $result['is_applied']          = in_array(
            wc_format_coupon_code( $resolved_code ),
            array_map( 'wc_format_coupon_code', WC()->cart->get_applied_coupons() ),
            true
        );

        if ( $expiry ) {
            $result['expiry_date']  = $expiry->format( 'Y-m-d' );
            $seconds_until_expiry   = $expiry->getTimestamp() - time();
            $result['expires_soon'] = $seconds_until_expiry > 0 && $seconds_until_expiry <= WEEK_IN_SECONDS;
        }

        $usage_limit = $resolved_coupon->get_usage_limit();
        $usage_count = $resolved_coupon->get_usage_count();
        if ( $usage_limit > 0 ) {
            $result['usage_remaining'] = max( 0, (int) $usage_limit - (int) $usage_count );
        }

        $subtotal = (float) WC()->cart->get_subtotal();
        if ( null !== $result['min_spend'] && $subtotal < $result['min_spend'] ) {
            $gap                         = max( 0, $result['min_spend'] - $subtotal );
            $result['spend_gap']         = (float) wc_format_decimal( $gap, wc_get_price_decimals() );
            $result['spend_gap_display'] = $this->format_price_for_language( $gap, $resolved_lang );
        }

        try {
            $discounts = new \WC_Discounts( WC()->cart );
            $discounts->is_coupon_valid( $resolved_coupon );
            $result['applicable'] = true;
            return $result;
        } catch ( \Throwable $e ) {
            $message = $this->localize_coupon_error_message( $e->getMessage(), $resolved_lang, $resolved_coupon );

            $result['reason']      = $message['message'];
            $result['reason_code'] = $message['code'];
            return $result;
        }
    }

    /**
     * Bootstrap the WooCommerce session/customer/cart for REST requests.
     *
     * @return bool
     */
    public function bootstrap_cart_context(): bool {
        if ( ! self::is_active() || ! function_exists( 'WC' ) ) {
            return false;
        }

        if ( null === WC()->session && class_exists( 'WC_Session_Handler' ) ) {
            WC()->session = new WC_Session_Handler();
            WC()->session->init();
        }

        if ( null === WC()->customer && class_exists( 'WC_Customer' ) ) {
            WC()->customer = new WC_Customer( get_current_user_id(), true );
        }

        if ( null === WC()->cart && class_exists( 'WC_Cart' ) ) {
            WC()->cart = new WC_Cart();
        }

        if ( ! WC()->cart ) {
            return false;
        }

        WC()->cart->get_cart();

        return true;
    }

    /**
     * Normalize a language code down to its slug.
     *
     * @param string $language Raw language.
     * @return string
     */
    private function resolve_language( string $language = '' ): string {
        $candidate = sanitize_text_field( $language );
        if ( empty( $candidate ) && function_exists( 'pll_current_language' ) ) {
            $candidate = (string) pll_current_language( 'slug' );
        }

        if ( empty( $candidate ) ) {
            $candidate = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
        }

        $parts = preg_split( '/[-_]/', strtolower( $candidate ) );
        return is_array( $parts ) && ! empty( $parts[0] ) ? $parts[0] : '';
    }

    /**
     * Resolve a WooCommerce store page URL in the requested language.
     *
     * REST requests often run without Polylang's page context, so the plain
     * WooCommerce helpers can fall back to the default-language permalink.
     *
     * @param string $page     WooCommerce page slug, e.g. cart or checkout.
     * @param string $language Optional language override.
     * @return string
     */
    public function get_store_page_url( string $page, string $language = '' ): string {
        $page = sanitize_key( $page );

        switch ( $page ) {
            case 'checkout':
                $fallback_url = function_exists( 'wc_get_checkout_url' ) ? wc_get_checkout_url() : home_url( '/checkout/' );
                break;
            case 'cart':
                $fallback_url = function_exists( 'wc_get_cart_url' ) ? wc_get_cart_url() : home_url( '/cart/' );
                break;
            default:
                return home_url( '/' );
        }

        $resolved_language = $this->resolve_language( $language );
        if ( empty( $resolved_language ) || ! function_exists( 'pll_get_post' ) || ! function_exists( 'wc_get_page_id' ) ) {
            return $fallback_url;
        }

        $page_id = (int) wc_get_page_id( $page );
        if ( $page_id <= 0 ) {
            return $fallback_url;
        }

        $translated_page_id = (int) pll_get_post( $page_id, $resolved_language );
        if ( $translated_page_id <= 0 ) {
            return $fallback_url;
        }

        $translated_url = get_permalink( $translated_page_id );
        return $translated_url ? $translated_url : $fallback_url;
    }

    /**
     * Return a normalized empty cart payload.
     *
     * @param string $language Optional language override.
     * @return array
     */
    private function get_empty_cart_snapshot( string $language = '' ): array {
        $resolved_language = $this->resolve_language( $language );
        $currency_override = BoostBot_Polylang_Context::override_currency_for_language( $resolved_language );
        $currency          = BoostBot_Polylang_Context::get_currency_for_language( $resolved_language );

        $snapshot = array(
            'count'                  => 0,
            'subtotal'               => $this->format_price_display( 0 ),
            'subtotal_amount'        => wc_format_decimal( 0, wc_get_price_decimals() ),
            'total'                  => $this->format_price_display( 0 ),
            'total_amount'           => wc_format_decimal( 0, wc_get_price_decimals() ),
            'discount_total'         => wc_format_decimal( 0, wc_get_price_decimals() ),
            'discount_total_display' => $this->format_price_display( 0 ),
            'currency_code'          => $currency['code'],
            'currency_symbol'        => $currency['symbol'],
            'applied_coupons'        => array(),
            'items'                  => array(),
            'checkout_url'           => $this->get_store_page_url( 'checkout', $resolved_language ),
            'cart_url'               => $this->get_store_page_url( 'cart', $resolved_language ),
            'is_empty'               => true,
        );

        BoostBot_Polylang_Context::restore_currency( $currency_override );

        return $snapshot;
    }

    /**
     * Format a raw amount as WooCommerce display text.
     *
     * @param float|int|string $amount Raw amount.
     * @return string
     */
    private function format_price_display( $amount ): string {
        return trim( wp_strip_all_tags( html_entity_decode( wc_price( (float) $amount ), ENT_QUOTES, 'UTF-8' ) ) );
    }

    /**
     * Format a price for a specific language/currency context.
     *
     * @param float|int|string $amount   Raw amount.
     * @param string           $language Optional language override.
     * @return string
     */
    private function format_price_for_language( $amount, string $language = '' ): string {
        $resolved_language = $this->resolve_language( $language );
        $currency_override = BoostBot_Polylang_Context::override_currency_for_language( $resolved_language );
        $formatted         = $this->format_price_display( $amount );

        BoostBot_Polylang_Context::restore_currency( $currency_override );

        return $formatted;
    }

    /**
     * Get the total cart discount amount including discount tax.
     *
     * @return float
     */
    private function get_cart_discount_total_amount(): float {
        $discount_total = (float) WC()->cart->get_discount_total();

        if ( method_exists( WC()->cart, 'get_discount_tax' ) ) {
            $discount_total += (float) WC()->cart->get_discount_tax();
        }

        return round( $discount_total, wc_get_price_decimals() );
    }

    /**
     * Get the applied discount amount for a single coupon code.
     *
     * @param string $coupon_code Coupon code.
     * @return float
     */
    private function get_coupon_discount_total_amount( string $coupon_code ): float {
        $discount_total = (float) WC()->cart->get_coupon_discount_amount( $coupon_code, false );

        if ( method_exists( WC()->cart, 'get_coupon_discount_tax_amount' ) ) {
            $discount_total += (float) WC()->cart->get_coupon_discount_tax_amount( $coupon_code );
        }

        return round( $discount_total, wc_get_price_decimals() );
    }

    /**
     * Resolve human-readable product names restricted by a coupon.
     *
     * @param WC_Coupon $coupon   Coupon object.
     * @param string    $language Optional language override.
     * @return array|null
     */
    private function get_coupon_product_names( \WC_Coupon $coupon, string $language = '' ): ?array {
        $names = array();

        foreach ( (array) $coupon->get_product_ids() as $product_id ) {
            $product_id = (int) $product_id;
            if ( $product_id <= 0 ) {
                continue;
            }

            if ( $language && function_exists( 'pll_get_post' ) ) {
                $translated_id = pll_get_post( $product_id, $language );
                if ( $translated_id ) {
                    $product_id = (int) $translated_id;
                }
            }

            $product = wc_get_product( $product_id );
            if ( $product ) {
                $names[] = $product->get_name();
            }
        }

        return ! empty( $names ) ? array_values( array_unique( $names ) ) : null;
    }

    /**
     * Resolve human-readable category names restricted by a coupon.
     *
     * @param WC_Coupon $coupon   Coupon object.
     * @param string    $language Optional language override.
     * @return array|null
     */
    private function get_coupon_category_names( \WC_Coupon $coupon, string $language = '' ): ?array {
        $names = array();

        foreach ( (array) $coupon->get_product_categories() as $category_id ) {
            $category_id = (int) $category_id;
            if ( $category_id <= 0 ) {
                continue;
            }

            if ( $language && function_exists( 'pll_get_term' ) ) {
                $translated_id = pll_get_term( $category_id, $language );
                if ( $translated_id ) {
                    $category_id = (int) $translated_id;
                }
            }

            $term = get_term( $category_id, 'product_cat' );
            if ( $term && ! is_wp_error( $term ) ) {
                $names[] = $term->name;
            }
        }

        return ! empty( $names ) ? array_values( array_unique( $names ) ) : null;
    }

    /**
     * Translate WooCommerce coupon validation messages into the active bot language.
     *
     * @param string    $message Coupon validation message.
     * @param string    $language Resolved language.
     * @param WC_Coupon $coupon Coupon object.
     * @return array{code:string,message:string}
     */
    private function localize_coupon_error_message( string $message, string $language, \WC_Coupon $coupon ): array {
        $normalized_message = strtolower( wp_strip_all_tags( $message ) );

        if ( false !== strpos( $normalized_message, 'expired' ) ) {
            return array(
                'code'    => 'expired',
                'message' => $this->get_localized_coupon_message( 'coupon_expired', $language ),
            );
        }

        if ( false !== strpos( $normalized_message, 'usage limit' ) ) {
            return array(
                'code'    => 'usage_limit_reached',
                'message' => $this->get_localized_coupon_message( 'coupon_usage_limit', $language ),
            );
        }

        if ( false !== strpos( $normalized_message, 'minimum spend' ) ) {
            return array(
                'code'    => 'minimum_spend_not_met',
                'message' => $this->get_localized_coupon_message(
                    'coupon_minimum_spend',
                    $language,
                    array( 'amount' => $this->format_price_for_language( (float) $coupon->get_minimum_amount(), $language ) )
                ),
            );
        }

        if ( false !== strpos( $normalized_message, 'maximum spend' ) ) {
            return array(
                'code'    => 'maximum_spend_exceeded',
                'message' => $this->get_localized_coupon_message(
                    'coupon_maximum_spend',
                    $language,
                    array( 'amount' => $this->format_price_for_language( (float) $coupon->get_maximum_amount(), $language ) )
                ),
            );
        }

        if (
            false !== strpos( $normalized_message, 'not applicable' )
            || false !== strpos( $normalized_message, 'not valid for the items' )
            || false !== strpos( $normalized_message, 'not valid for selected products' )
            || false !== strpos( $normalized_message, 'not valid for your cart' )
        ) {
            return array(
                'code'    => 'not_eligible',
                'message' => $this->get_localized_coupon_message( 'coupon_not_eligible', $language ),
            );
        }

        return array(
            'code'    => 'coupon_invalid',
            'message' => $this->get_localized_coupon_message( 'coupon_invalid', $language ),
        );
    }

    /**
     * Return localized coupon/cart copy by key.
     *
     * @param string $key          Message key.
     * @param string $language     Optional language override.
     * @param array  $replacements Placeholder replacements.
     * @return string
     */
    private function get_localized_coupon_message( string $key, string $language = '', array $replacements = array() ): string {
        $lang = $this->resolve_language( $language );

        $messages = array(
            'en' => array(
                'woo_inactive'           => 'WooCommerce is not active',
                'cart_unavailable'       => 'Cart is unavailable right now',
                'coupon_missing'         => 'Coupon code is required',
                'coupon_invalid'         => 'Coupon is invalid',
                'coupon_already_applied' => 'Coupon is already applied',
                'coupon_not_applied'     => 'Coupon is not applied to the cart',
                'coupon_not_eligible'    => 'Coupon is not eligible for your cart',
                'coupon_expired'         => 'Coupon has expired',
                'coupon_usage_limit'     => 'Coupon usage limit reached',
                'coupon_minimum_spend'   => 'Minimum spend of {amount} not met',
                'coupon_maximum_spend'   => 'Maximum spend of {amount} exceeded',
                'coupon_apply_failed'    => 'Could not apply coupon right now',
                'coupon_applied'         => 'Coupon {code} applied!',
                'coupon_removed'         => 'Coupon {code} removed',
            ),
            'he' => array(
                'woo_inactive'           => 'WooCommerce לא פעיל',
                'cart_unavailable'       => 'העגלה אינה זמינה כרגע',
                'coupon_missing'         => 'יש להזין קוד קופון',
                'coupon_invalid'         => 'הקופון אינו תקין',
                'coupon_already_applied' => 'הקופון כבר הופעל',
                'coupon_not_applied'     => 'הקופון לא מופעל כרגע על העגלה',
                'coupon_not_eligible'    => 'הקופון לא תקף לעגלה שלך',
                'coupon_expired'         => 'הקופון פג תוקף',
                'coupon_usage_limit'     => 'הקופון הגיע למגבלת השימוש',
                'coupon_minimum_spend'   => 'סכום מינימום של {amount} לא הושג',
                'coupon_maximum_spend'   => 'חרגת מסכום המקסימום של {amount} עבור הקופון',
                'coupon_apply_failed'    => 'לא ניתן היה להפעיל את הקופון כרגע',
                'coupon_applied'         => 'הקופון {code} הופעל!',
                'coupon_removed'         => 'הקופון {code} הוסר',
            ),
        );

        $dictionary = $messages[ $lang ] ?? $messages['en'];
        $template   = $dictionary[ $key ] ?? $messages['en'][ $key ] ?? $key;

        foreach ( $replacements as $placeholder => $value ) {
            $template = str_replace( '{' . $placeholder . '}', (string) $value, $template );
        }

        return $template;
    }

    /**
     * Get all product categories.
     *
     * @param bool $hide_empty Hide categories without products.
     * @return array Categories array.
     */
    public function get_categories( bool $hide_empty = true, ?string $language = null ): array {
        if ( ! self::is_active() ) {
            return array();
        }

        $args = array(
            'taxonomy'   => 'product_cat',
            'hide_empty' => $hide_empty,
        );
        if ( $language ) {
            $args['lang'] = $language;
        }

        $terms = get_terms( $args );

        if ( is_wp_error( $terms ) ) {
            return array();
        }

        return array_map(
            fn( $term ) => array(
                'id'    => $term->term_id,
                'name'  => $term->name,
                'slug'  => $term->slug,
                'count' => $term->count,
                'url'   => get_term_link( $term ),
            ),
            $terms
        );
    }

    /**
     * Get product for chat context.
     *
     * Returns simplified product info for AI context.
     *
     * @param int $product_id Product ID.
     * @return string Product description for AI.
     */
    public function get_product_context( int $product_id ): string {
        $product = $this->get_product( $product_id );

        if ( ! $product ) {
            return '';
        }

        $context = sprintf(
            "מוצר: %s\nמחיר: %s%s\nתיאור: %s\nקטגוריות: %s\nזמינות: %s",
            $product['name'],
            $product['currency'],
            $product['price'],
            $product['short_description'],
            implode( ', ', $product['categories'] ),
            $product['in_stock'] ? 'במלאי' : 'אזל מהמלאי'
        );

        if ( $product['is_on_sale'] ) {
            $context .= sprintf( "\n🔥 במבצע! מחיר רגיל: %s%s", $product['currency'], $product['regular_price'] );
        }

        return $context;
    }

    /**
     * Check if current page is a product page.
     *
     * @return int|false Product ID or false.
     */
    public static function get_current_product_id() {
        if ( ! self::is_active() ) {
            return false;
        }

        if ( is_product() ) {
            return get_the_ID();
        }

        return false;
    }

    /**
     * Check if current page is a shop/category page.
     *
     * @return array|false Category info or false.
     */
    public static function get_current_category() {
        if ( ! self::is_active() ) {
            return false;
        }

        if ( is_product_category() ) {
            $term = get_queried_object();
            return array(
                'id'   => $term->term_id,
                'name' => $term->name,
                'slug' => $term->slug,
            );
        }

        return false;
    }
}








