<?php
/**
 * Author: Rymera Web Co.
 *
 * @package SAAI\REST\Chat
 */

namespace SAAI\REST\Chat;

use SAAI\Abstracts\Abstract_REST;
use SAAI\Traits\Singleton_Trait;
use SAAI\Classes\Chat\Chat_Feedback;
use WC_Order;
use WC_Product;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

defined( 'ABSPATH' ) || exit;

/**
 * Chat Tools REST API controller class.
 *
 * @since 1.0.8
 */
class Chat_Tools extends Abstract_REST {

    use Singleton_Trait;

    /**
     * Holds the class instance object.
     *
     * @since 1.0.8
     * @var Chat_Tools $instance object
     */
    protected static $instance;

    /**
     * REST constructor.
     *
     * @since 1.0.8
     */
    public function __construct() {
    }

    /**
     * Works as constructor for this class.
     *
     * @since 1.0.8
     * @return void
     */
    public function register_plugin_routes() {
        $this->rest_base = 'chat';
        parent::register_plugin_routes();
    }

    /**
     * Register the routes for Chat Tools.
     *
     * @since 1.0.8
     * @return void
     */
    public function register_routes() {
        // Product prices endpoint.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/product-prices",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'get_product_prices' ),
                'permission_callback' => array( $this, 'validate_temp_token_permissions' ),
                'args'                => array(
                    'products' => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => 'Comma separated list of product IDs, slugs, or names',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'token'    => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => 'Temporary authentication token with session ID',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        // Order data endpoint.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/order-data",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'get_order_data' ),
                'permission_callback' => array( $this, 'validate_temp_token_permissions' ),
                'args'                => array(
                    'order_id' => array(
                        'required'          => true,
                        'type'              => 'integer',
                        'description'       => 'WooCommerce order ID',
                        'sanitize_callback' => 'absint',
                    ),
                    'token'    => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => 'Temporary authentication token with session ID',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        // Product reviews endpoint for n8n.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/product-reviews",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'get_product_reviews' ),
                'permission_callback' => array( $this, 'validate_temp_token_permissions' ),
                'args'                => array(
                    'product_id' => array(
                        'required'          => true,
                        'type'              => 'integer',
                        'description'       => 'Product ID to get reviews for',
                        'sanitize_callback' => 'absint',
                    ),
                    'limit'      => array(
                        'required'          => false,
                        'type'              => 'integer',
                        'default'           => 50,
                        'description'       => 'Number of reviews to retrieve (default: 50, max: 200)',
                        'sanitize_callback' => 'absint',
                    ),
                    'token'      => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => 'Temporary authentication token with session ID',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        // Search products endpoint for AI tools (upsells, etc.).
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/search-products",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'search_products' ),
                'permission_callback' => array( $this, 'validate_temp_token_permissions' ),
                'args'                => array(
                    'query'     => array(
                        'required'          => false,
                        'type'              => 'string',
                        'default'           => '',
                        'description'       => 'Keyword search term for product name or description.',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'category'  => array(
                        'required'          => false,
                        'type'              => 'string',
                        'default'           => '',
                        'description'       => 'Product category name or slug to filter by.',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'min_price' => array(
                        'required'          => false,
                        'type'              => 'number',
                        'description'       => 'Minimum product price.',
                        'sanitize_callback' => 'wc_format_decimal',
                    ),
                    'max_price' => array(
                        'required'          => false,
                        'type'              => 'number',
                        'description'       => 'Maximum product price.',
                        'sanitize_callback' => 'wc_format_decimal',
                    ),
                    'exclude'   => array(
                        'required'          => false,
                        'type'              => 'string',
                        'default'           => '',
                        'description'       => 'Comma-separated product IDs to exclude.',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                    'limit'     => array(
                        'required'          => false,
                        'type'              => 'integer',
                        'default'           => 20,
                        'description'       => 'Max results to return (default 20, max 50).',
                        'sanitize_callback' => 'absint',
                    ),
                    'token'     => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => 'Temporary authentication token with session ID.',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        // Chat settings endpoint for AI chat.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/chat-settings",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'get_chat_settings' ),
                'permission_callback' => array( $this, 'validate_temp_token_permissions' ),
                'args'                => array(
                    'token' => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => 'Temporary authentication token with session ID',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );

        // Available coupons endpoint for AI coupon offering.
        register_rest_route(
            $this->namespace,
            "/$this->rest_base/available-coupons",
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'get_available_coupons' ),
                'permission_callback' => array( $this, 'validate_temp_token_permissions' ),
                'args'                => array(
                    'token' => array(
                        'required'          => true,
                        'type'              => 'string',
                        'description'       => 'Temporary authentication token with session ID.',
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            )
        );
    }

    /**
     * Validate temporary token permissions.
     *
     * @since 1.0.8
     * @param WP_REST_Request $request The request object.
     * @return bool|WP_Error True if valid token, error otherwise.
     */
    public function validate_temp_token_permissions( $request ) {
        // Allow access to the endpoint for admins.
        if ( current_user_can( 'manage_options' ) ) {
            return true;
        }

        list( $session_id, $token ) = explode( ':::', $request->get_param( 'token' ) );

        if ( empty( $session_id ) || empty( $token ) ) {
            return new WP_Error(
                'missing_token',
                __( 'Temporary token is required.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        $session_data = get_transient( "saai_session_$session_id" );

        if ( false === $session_data || ! is_array( $session_data ) || ! isset( $session_data['token'] ) ) {
            return new WP_Error(
                'invalid_token',
                __( 'Invalid or expired temporary token.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        // Check if the provided token matches the session token.
        if ( $session_data['token'] !== $token ) {
            return new WP_Error(
                'token_mismatch',
                __( 'Token does not match current session.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        // Restore the original user context so downstream code
        // (e.g. current_user_can, wp_get_current_user) works correctly.
        // This is safe because token validation (expiry + signature) is fully
        // completed above, and session data is stored server-side via set_transient().
        $user_id = absint( $session_data['user_id'] );

        if ( $user_id > 0 ) {
            wp_set_current_user( $user_id );
        }

        return true;
    }

    /**
     * Get product prices.
     *
     * @since 1.0.8
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function get_product_prices( $request ) {
        $products = $request->get_param( 'products' );

        if ( empty( $products ) ) {
            return new WP_Error(
                'invalid_products',
                __( 'Products parameter must be a non-empty comma separated list of product IDs, slugs, or names.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 400 )
            );
        }

        $products = explode( ',', $products );
        $results  = array();

        foreach ( $products as $identifier ) {
            $product = $this->find_product_by_identifier( $identifier );

            if ( ! $product ) {
                // Skip products that aren't found as per requirement.
                continue;
            }

            $price_data = $this->get_product_pricing_data( $product );
            if ( $price_data ) {
                $results[] = $price_data;
            }
        }

        return new WP_REST_Response( $results, 200 );
    }

    /**
     * Get order data.
     *
     * @since 1.0.8
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function get_order_data( $request ) {
        $order_id = $request->get_param( 'order_id' );

        if ( empty( $order_id ) ) {
            return new WP_Error(
                'invalid_order_id',
                __( 'Order ID is required.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 400 )
            );
        }

        // Get session data to validate user access.
        list( $session_id, $token ) = explode( ':::', $request->get_param( 'token' ) );

        // Do not allow guest sessions to access order data.
        if ( strpos( $session_id, 'guest_' ) === 0 ) {
            return new WP_Error(
                'invalid_session',
                __( 'Invalid session data.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        // Get the order object.
        $order = wc_get_order( $order_id );

        if ( ! $order || ! $order->get_customer_id() ) {
            return new WP_Error(
                'order_not_found',
                __( 'Order not found.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 404 )
            );
        }

        $session_data = get_transient( "saai_session_$session_id" );

        if ( ! $session_data ) {
            return new WP_Error(
                'invalid_session',
                __( 'Invalid session data.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 401 )
            );
        }

        $session_user_id = $session_data['user_id'];

        // Check if session user ID matches order customer ID.
        if ( (int) $session_user_id !== (int) $order->get_customer_id() ) {
            return new WP_Error(
                'order_access_denied',
                __( 'You do not have permission to access this order.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 403 )
            );
        }

        // Get order data.
        $order_data = $this->get_formatted_order_data( $order );

        return new WP_REST_Response( $order_data, 200 );
    }

    /**
     * Get product reviews for n8n integration.
     *
     * @since 1.0.8
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function get_product_reviews( $request ) {
        $product_id  = $request->get_param( 'product_id' );
        $limit_param = $request->get_param( 'limit' );
        $limit       = $limit_param ? $limit_param : 50;

        // Validate limit parameter.
        if ( $limit > 200 ) {
            $limit = 200;
        }

        // Validate product exists.
        $product = wc_get_product( $product_id );
        if ( ! $product ) {
            return new WP_Error(
                'product_not_found',
                __( 'Product not found.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 404 )
            );
        }

        // Initialize Review_Summary and query reviews.
        $review_summary = new \SAAI\Classes\Review_Summary( $product_id );
        $reviews        = $review_summary->query_review_objects(
            array(
                'number' => $limit,
            )
        );

        // Get total count for pagination info.
        $total_reviews = $review_summary->get_total_reviews_count();

        // Format reviews for API response.
        $formatted_reviews = array_map( array( $this, 'format_review_for_api' ), $reviews );

        $response_data = array(
            'product_id'    => $product_id,
            'product_name'  => $product->get_name(),
            'limit'         => $limit,
            'total_reviews' => $total_reviews,
            'returned'      => count( $formatted_reviews ),
            'reviews'       => $formatted_reviews,
        );

        return new WP_REST_Response( $response_data, 200 );
    }

    /**
     * Get chat settings for AI chat.
     *
     * @since 1.0.8
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function get_chat_settings( $request ) {
        // Get feedback settings filtered by current plan.
        $feedback_settings = Chat_Feedback::get_feedback_settings_for_plan();

        // Get post types settings for wholesale data flag.
        $post_types_settings    = get_option( Chat_Post_Types::OPTION_KEY, array() );
        $include_wholesale_data = isset( $post_types_settings['product']['include_wholesale_data'] )
            ? $post_types_settings['product']['include_wholesale_data']
            : false;

        // Get coupon offering setting.
        $widget_settings       = Chat_Widget_Settings::get_chat_widget_settings();
        $allow_coupon_offering = ! empty( $widget_settings['allow_coupon_offering'] );

        // Build chat settings array.
        $chat_settings = array(
            'feedback'               => $feedback_settings,
            'include_wholesale_data' => $include_wholesale_data,
            'allow_coupon_offering'  => $allow_coupon_offering,
        );

        // Include available coupons directly in chat settings when coupon offering is enabled.
        if ( $allow_coupon_offering ) {
            $chat_settings['available_coupons'] = $this->get_available_coupons_data( $widget_settings );
        }

        /**
         * Filter chat settings before returning to AI.
         *
         * @since 1.0.8
         * @param array $chat_settings Chat settings including feedback and other settings.
         */
        $chat_settings = apply_filters( 'saai_ai_chat_settings', $chat_settings );

        return new WP_REST_Response( $chat_settings, 200 );
    }

    /**
     * Get available coupons for AI coupon offering.
     *
     * Returns the admin-selected coupons that are valid and can be offered
     * to customers by the AI chatbot during conversations.
     *
     * @since 1.3.0
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function get_available_coupons( $request ) {
        // Check if coupon offering is enabled.
        $widget_settings = Chat_Widget_Settings::get_chat_widget_settings();
        if ( empty( $widget_settings['allow_coupon_offering'] ) ) {
            return new WP_Error(
                'coupon_offering_disabled',
                __( 'Coupon offering is not enabled.', 'storeagent-ai-for-woocommerce' ),
                array( 'status' => 403 )
            );
        }

        $coupons = $this->get_available_coupons_data( $widget_settings );

        return new WP_REST_Response(
            array(
                'total_found' => count( $coupons ),
                'coupons'     => $coupons,
            ),
            200
        );
    }

    /**
     * Search products for AI tools.
     *
     * Returns compact product data filtered by keyword, category, price range, etc.
     * Used by AI agents (e.g., Product Upsells) to dynamically query the catalog.
     *
     * @since 1.2.0
     * @param WP_REST_Request $request The request object.
     * @return WP_REST_Response|WP_Error The response object or error.
     */
    public function search_products( $request ) {
        $query_term = $request->get_param( 'query' );
        $category   = $request->get_param( 'category' );
        $min_price  = $request->get_param( 'min_price' );
        $max_price  = $request->get_param( 'max_price' );
        $exclude    = $request->get_param( 'exclude' );
        $limit      = min( $request->get_param( 'limit' ) ?? 20, 50 );

        $args = array(
            'status'  => 'publish',
            'limit'   => $limit,
            'type'    => array( 'simple', 'variable', 'grouped', 'external' ),
            'orderby' => 'date',
            'order'   => 'DESC',
        );

        // Keyword search.
        if ( ! empty( $query_term ) ) {
            $args['s'] = $query_term;
        }

        // Category filter.
        if ( ! empty( $category ) ) {
            $term = get_term_by( 'slug', sanitize_title( $category ), 'product_cat' );

            if ( ! $term ) {
                $term = get_term_by( 'name', $category, 'product_cat' );
            }

            if ( $term ) {
                $args['category'] = array( $term->slug );
            }
        }

        // Exclude specific product IDs.
        if ( ! empty( $exclude ) ) {
            $exclude_ids     = array_map( 'absint', explode( ',', $exclude ) );
            $args['exclude'] = array_filter( $exclude_ids );
        }

        $products = wc_get_products( $args );
        $results  = array();

        foreach ( $products as $product ) {
            $price = (float) $product->get_price();

            // Price range filter (post-query since wc_get_products doesn't support it natively).
            if ( null !== $min_price && $price < $min_price ) {
                continue;
            }

            if ( null !== $max_price && $price > $max_price ) {
                continue;
            }

            $categories = get_the_terms( $product->get_id(), 'product_cat' );
            $cat_names  = ( $categories && ! is_wp_error( $categories ) )
                ? wp_list_pluck( $categories, 'name' )
                : array();

            $tags      = get_the_terms( $product->get_id(), 'product_tag' );
            $tag_names = ( $tags && ! is_wp_error( $tags ) )
                ? wp_list_pluck( $tags, 'name' )
                : array();

            $results[] = array(
                'id'                => $product->get_id(),
                'name'              => $product->get_name(),
                'short_description' => wp_strip_all_tags( $product->get_short_description() ),
                'price'             => $product->get_price(),
                'regular_price'     => $product->get_regular_price(),
                'categories'        => $cat_names,
                'tags'              => $tag_names,
                'type'              => $product->get_type(),
                'average_rating'    => $product->get_average_rating(),
            );
        }

        return new WP_REST_Response(
            array(
                'total_found' => count( $results ),
                'products'    => $results,
            ),
            200
        );
    }

    /**
     * Format a single review for API response.
     *
     * @since 1.0.8
     * @param \WP_Comment $review Review comment object.
     * @return array
     */
    private function format_review_for_api( $review ) {
        $rating = get_comment_meta( $review->comment_ID, 'rating', true );

        return array(
            'id'       => $review->comment_ID,
            'content'  => $review->comment_content,
            'rating'   => $rating ? absint( $rating ) : null,
            'date'     => $review->comment_date,
            'date_gmt' => $review->comment_date_gmt,
            'status'   => $review->comment_approved,
            'verified' => wc_review_is_from_verified_owner( $review->comment_ID ),
        );
    }

    /**
     * Get available coupons data for inclusion in chat settings.
     *
     * Extracts valid, non-expired coupons with their instructions
     * for the AI to use during conversations.
     *
     * @since 1.3.0
     * @param array $widget_settings The chat widget settings.
     * @return array Array of coupon data.
     */
    private function get_available_coupons_data( $widget_settings ) {
        $coupon_ids          = ! empty( $widget_settings['offering_coupon_ids'] ) ? $widget_settings['offering_coupon_ids'] : array();
        $coupon_instructions = ! empty( $widget_settings['offering_coupon_instructions'] ) ? $widget_settings['offering_coupon_instructions'] : array();

        if ( empty( $coupon_ids ) ) {
            return array();
        }

        $coupons = array();

        foreach ( $coupon_ids as $coupon_id ) {
            $coupon = new \WC_Coupon( absint( $coupon_id ) );

            // Skip if coupon does not exist.
            if ( ! $coupon->get_id() ) {
                continue;
            }

            // Skip expired coupons.
            $expiry_date = $coupon->get_date_expires();
            if ( $expiry_date && $expiry_date->getTimestamp() < time() ) {
                continue;
            }

            // Skip coupons that have exceeded their usage limit.
            $usage_limit = $coupon->get_usage_limit();
            if ( $usage_limit > 0 && $coupon->get_usage_count() >= $usage_limit ) {
                continue;
            }

            $instruction = isset( $coupon_instructions[ (string) $coupon_id ] ) ? $coupon_instructions[ (string) $coupon_id ] : '';

            $coupons[] = array(
                'code'        => $coupon->get_code(),
                'description' => $coupon->get_description(),
                'instruction' => $instruction,
            );
        }

        return $coupons;
    }

    /**
     * Find product by identifier (ID, slug, or name).
     *
     * @since 1.0.8
     * @param string|int $identifier Product ID, slug, or name.
     * @return WC_Product|false Product object or false if not found.
     */
    private function find_product_by_identifier( $identifier ) {
        // Try as ID first.
        if ( is_numeric( $identifier ) ) {
            $product = wc_get_product( absint( $identifier ) );
            if ( $product && ! is_wp_error( $product ) ) {
                return $product;
            }
        }

        // Try as slug.
        $post = get_page_by_path( sanitize_title( $identifier ), OBJECT, 'product' );
        if ( $post ) {
            $product = wc_get_product( $post->ID );
            if ( $product && ! is_wp_error( $product ) ) {
                return $product;
            }
        }

        // Try as product name.
        $query = new \WP_Query(
            array(
                'post_type'      => 'product',
                'posts_per_page' => 1,
                'post_status'    => 'publish',
                'fields'         => 'ids',
                's'              => $identifier,
            )
        );

        if ( ! empty( $query->posts ) ) {
            $product = wc_get_product( $query->posts[0] );
            if ( $product && ! is_wp_error( $product ) ) {
                return $product;
            }
        }

        return false;
    }

    /**
     * Get pricing data for a product.
     *
     * @since 1.0.8
     * @param WC_Product $product The product object.
     * @return array|false Product pricing data or false on failure.
     */
    private function get_product_pricing_data( $product ) {
        if ( ! $product instanceof WC_Product ) {
            return false;
        }

        $price_data = array(
            'id'              => $product->get_id(),
            'name'            => $product->get_name(),
            'slug'            => $product->get_slug(),
            'regular_price'   => $product->get_regular_price(),
            'sale_price'      => $product->get_sale_price(),
            'price'           => $product->get_price(),
            'currency'        => get_woocommerce_currency(),
            'currency_symbol' => get_woocommerce_currency_symbol(),
        );

        /**
         * Filter product pricing data for third-party plugin support.
         *
         * @since 1.0.8
         * @param array      $price_data The default pricing data.
         * @param WC_Product $product    The product object.
         */
        $price_data = apply_filters( 'saai_product_pricing_data', $price_data, $product );

        return $price_data;
    }

    /**
     * Get formatted order data.
     *
     * @since 1.0.8
     * @param WC_Order $order The order object.
     * @return array Formatted order data.
     */
    private function get_formatted_order_data( $order ) {
        if ( ! $order instanceof WC_Order ) {
            return array();
        }

        $order_data = array(
            'id'                   => $order->get_id(),
            'order_number'         => $order->get_order_number(),
            'status'               => $order->get_status(),
            'status_name'          => wc_get_order_status_name( $order->get_status() ),
            'date_created'         => $order->get_date_created() ? $order->get_date_created()->format( 'Y-m-d H:i:s' ) : '',
            'date_modified'        => $order->get_date_modified() ? $order->get_date_modified()->format( 'Y-m-d H:i:s' ) : '',
            'currency'             => $order->get_currency(),
            'total'                => $order->get_total(),
            'subtotal'             => $order->get_subtotal(),
            'tax_total'            => $order->get_total_tax(),
            'shipping_total'       => $order->get_shipping_total(),
            'discount_total'       => $order->get_total_discount(),
            'payment_method'       => $order->get_payment_method(),
            'payment_method_title' => $order->get_payment_method_title(),
            'customer_id'          => $order->get_customer_id(),
            'customer_note'        => $order->get_customer_note(),
        );

        // Add billing address (excluding all personal and identifying data).
        $order_data['billing'] = array(
            'city'     => $order->get_billing_city(),
            'state'    => $order->get_billing_state(),
            'postcode' => $order->get_billing_postcode(),
            'country'  => $order->get_billing_country(),
        );

        // Add shipping address (excluding all personal and identifying data).
        $order_data['shipping'] = array(
            'city'     => $order->get_shipping_city(),
            'state'    => $order->get_shipping_state(),
            'postcode' => $order->get_shipping_postcode(),
            'country'  => $order->get_shipping_country(),
        );

        // Add line items.
        $line_items = array();
        foreach ( $order->get_items() as $item_id => $item ) {
            /*
             * @var WC_Order_Item_Product $item Order item product.
             */
            $product = $item->get_product(); // phpcs:ignore

            $line_item = array(
                'id'           => $item_id,
                'product_id'   => $item->get_product_id(), // phpcs:ignore
                'variation_id' => $item->get_variation_id(), // phpcs:ignore
                'name'         => $item->get_name(),
                'quantity'     => $item->get_quantity(),
                'subtotal'     => $item->get_subtotal(), // phpcs:ignore
                'total'        => $item->get_total(), // phpcs:ignore
                'tax_total'    => $item->get_total_tax(), // phpcs:ignore
            );

            // Add product details if available.
            if ( $product ) {
                $line_item['product_sku']   = $product->get_sku();
                $line_item['product_price'] = $product->get_price();
            }

            $line_items[] = $line_item;
        }
        $order_data['line_items'] = $line_items;

        // Add shipping lines.
        $shipping_lines = array();
        foreach ( $order->get_shipping_methods() as $shipping_id => $shipping ) {
            $shipping_lines[] = array(
                'id'           => $shipping_id,
                'method_title' => $shipping->get_method_title(),
                'method_id'    => $shipping->get_method_id(),
                'total'        => $shipping->get_total(),
                'tax_total'    => $shipping->get_total_tax(),
            );
        }
        $order_data['shipping_lines'] = $shipping_lines;

        /**
         * Filter order data for third-party plugin support.
         *
         * @since 1.0.8
         * @param array    $order_data The formatted order data.
         * @param WC_Order $order      The order object.
         */
        $order_data = apply_filters( 'saai_order_data', $order_data, $order );

        return $order_data;
    }
}
