<?php
/**
 * GGM Commerce Product Comparison Class
 *
 * Handles product comparison functionality including storage, retrieval, and management.
 * Uses cookie storage for both logged-in users and guests (comparison is session-based).
 *
 * @package GGM_Commerce
 */

defined( 'ABSPATH' ) || exit;

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

/**
 * Class GGM_Commerce_Product_Comparison
 */
class GGM_Commerce_Product_Comparison {

    /**
     * Cookie name for comparison list.
     *
     * @var string
     */
    const COOKIE_NAME = 'ggmc_compare';

    /**
     * Cookie expiration in days.
     *
     * @var int
     */
    const COOKIE_EXPIRATION_DAYS = 30;

    /**
     * Default maximum number of products that can be compared.
     * This constant is kept for backwards compatibility.
     * Use get_max_products() to get the configured value.
     *
     * @var int
     */
    const MAX_PRODUCTS = 4;

    /**
     * Get the maximum number of products that can be compared.
     * Reads from widget controls option, falls back to constant.
     *
     * @return int
     */
    public static function get_max_products() {
        $widget_controls = get_option( 'ggm_commerce_widget_controls', array() );
        return isset( $widget_controls['comparison_max_products'] )
            ? absint( $widget_controls['comparison_max_products'] )
            : self::MAX_PRODUCTS;
    }

    /**
     * Singleton instance.
     *
     * @var GGM_Commerce_Product_Comparison|null
     */
    private static $instance = null;

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

    /**
     * Constructor.
     */
    private function __construct() {
        // Register AJAX actions for both logged-in and guest users.
        add_action( 'wp_ajax_ggmc_compare_add', array( $this, 'ajax_add_to_compare' ) );
        add_action( 'wp_ajax_nopriv_ggmc_compare_add', array( $this, 'ajax_add_to_compare' ) );

        add_action( 'wp_ajax_ggmc_compare_remove', array( $this, 'ajax_remove_from_compare' ) );
        add_action( 'wp_ajax_nopriv_ggmc_compare_remove', array( $this, 'ajax_remove_from_compare' ) );

        add_action( 'wp_ajax_ggmc_compare_toggle', array( $this, 'ajax_toggle_compare' ) );
        add_action( 'wp_ajax_nopriv_ggmc_compare_toggle', array( $this, 'ajax_toggle_compare' ) );

        add_action( 'wp_ajax_ggmc_compare_get', array( $this, 'ajax_get_compare' ) );
        add_action( 'wp_ajax_nopriv_ggmc_compare_get', array( $this, 'ajax_get_compare' ) );

        add_action( 'wp_ajax_ggmc_compare_clear', array( $this, 'ajax_clear_compare' ) );
        add_action( 'wp_ajax_nopriv_ggmc_compare_clear', array( $this, 'ajax_clear_compare' ) );

        // Hook into widget activation to create comparison page.
        add_action( 'ggm_commerce_widget_activated', array( $this, 'on_widget_activated' ) );
    }

    /**
     * Check if Product Comparison 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( 'product-comparison' );
    }

    /**
     * Handle widget activation - create comparison page if activated.
     *
     * @param string $widget_slug The slug of the widget that was activated.
     */
    public function on_widget_activated( $widget_slug ) {
        if ( $widget_slug !== 'product-comparison' ) {
            return;
        }

        // Create the comparison page.
        if ( class_exists( 'GGM_Commerce_Page_Builder' ) ) {
            \GGM_Commerce_Page_Builder::create_comparison_page();
        }
    }

    /**
     * Get comparison list from cookie.
     *
     * @return array Product IDs in comparison list.
     */
    public function get_product_ids() {
        if ( isset( $_COOKIE[ self::COOKIE_NAME ] ) ) {
            // Get the raw cookie value and unslash it
            $cookie_value = wp_unslash( $_COOKIE[ self::COOKIE_NAME ] );

            // Try to decode directly first
            $compare_list = json_decode( $cookie_value, true );

            // If that failed, try URL decoding first (browser might encode it)
            if ( ! is_array( $compare_list ) ) {
                $compare_list = json_decode( urldecode( $cookie_value ), true );
            }

            if ( is_array( $compare_list ) ) {
                // Sanitize by ensuring all values are integers
                return array_values( array_filter( array_map( 'intval', $compare_list ) ) );
            }
        }
        return array();
    }

    /**
     * Save comparison list to cookie.
     *
     * @param array $product_ids Product IDs to save.
     */
    private function save_compare_list( $product_ids ) {
        // Ensure we don't exceed max products.
        $product_ids = array_slice( array_unique( array_map( 'intval', $product_ids ) ), 0, self::get_max_products() );

        $expiration = time() + ( self::COOKIE_EXPIRATION_DAYS * DAY_IN_SECONDS );
        $value      = wp_json_encode( array_values( $product_ids ) );

        // Set cookie - use '/' as path to ensure it works across all pages.
        // Don't require secure flag to work on local dev environments without HTTPS.
        setcookie(
            self::COOKIE_NAME,
            $value,
            array(
                'expires'  => $expiration,
                'path'     => '/',
                'domain'   => '',
                'secure'   => false, // Allow HTTP for local development.
                'httponly' => false, // Allow JS access for immediate UI updates.
                'samesite' => 'Lax',
            )
        );

        // Also update $_COOKIE for immediate access in same request.
        $_COOKIE[ self::COOKIE_NAME ] = $value;
    }

    /**
     * Add a product to the comparison list.
     *
     * @param int $product_id Product ID to add.
     * @return array Result with success status and message.
     */
    public function add_item( $product_id ) {
        $product_id = absint( $product_id );

        if ( ! $product_id ) {
            return array(
                'success' => false,
                'message' => __( 'Invalid product ID.', 'ggm-commerce' ),
            );
        }

        // Verify product exists.
        if ( ! $this->product_exists( $product_id ) ) {
            return array(
                'success' => false,
                'message' => __( 'Product not found.', 'ggm-commerce' ),
            );
        }

        $compare_list = $this->get_product_ids();

        // Check if already in list.
        if ( in_array( $product_id, $compare_list, true ) ) {
            return array(
                'success'     => true,
                'message'     => __( 'Product already in comparison list.', 'ggm-commerce' ),
                'action'      => 'exists',
                'count'       => count( $compare_list ),
                'product_ids' => $compare_list,
            );
        }

        // Check if max products reached.
        $max_products = self::get_max_products();
        if ( count( $compare_list ) >= $max_products ) {
            return array(
                'success'     => false,
                'message'     => sprintf(
                    /* translators: %d: maximum number of products */
                    __( 'Maximum of %d products can be compared. Remove a product first.', 'ggm-commerce' ),
                    $max_products
                ),
                'count'       => count( $compare_list ),
                'product_ids' => $compare_list,
            );
        }

        $compare_list[] = $product_id;
        $this->save_compare_list( $compare_list );

        return array(
            'success'     => true,
            'message'     => __( 'Product added to comparison.', 'ggm-commerce' ),
            'action'      => 'added',
            'count'       => count( $compare_list ),
            'product_ids' => $compare_list,
        );
    }

    /**
     * Remove a product from the comparison list.
     *
     * @param int $product_id Product ID to remove.
     * @return array Result with success status and message.
     */
    public function remove_item( $product_id ) {
        $product_id = absint( $product_id );

        if ( ! $product_id ) {
            return array(
                'success' => false,
                'message' => __( 'Invalid product ID.', 'ggm-commerce' ),
            );
        }

        $compare_list = $this->get_product_ids();
        $key          = array_search( $product_id, $compare_list, true );

        if ( false === $key ) {
            return array(
                'success'     => true,
                'message'     => __( 'Product not in comparison list.', 'ggm-commerce' ),
                'action'      => 'not_found',
                'count'       => count( $compare_list ),
                'product_ids' => $compare_list,
            );
        }

        unset( $compare_list[ $key ] );
        $compare_list = array_values( $compare_list ); // Re-index array.
        $this->save_compare_list( $compare_list );

        return array(
            'success'     => true,
            'message'     => __( 'Product removed from comparison.', 'ggm-commerce' ),
            'action'      => 'removed',
            'count'       => count( $compare_list ),
            'product_ids' => $compare_list,
        );
    }

    /**
     * Toggle a product in the comparison list (add if not present, remove if present).
     *
     * @param int $product_id Product ID to toggle.
     * @return array Result with success status and action taken.
     */
    public function toggle_item( $product_id ) {
        $product_id = absint( $product_id );

        if ( $this->is_in_compare( $product_id ) ) {
            return $this->remove_item( $product_id );
        }

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

    /**
     * Check if a product is in the comparison list.
     *
     * @param int $product_id Product ID to check.
     * @return bool True if product is in comparison list.
     */
    public function is_in_compare( $product_id ) {
        $product_id = absint( $product_id );

        if ( ! $product_id ) {
            return false;
        }

        $compare_list = $this->get_product_ids();
        return in_array( $product_id, $compare_list, true );
    }

    /**
     * Get comparison count.
     *
     * @return int Number of items in comparison list.
     */
    public function get_count() {
        return count( $this->get_product_ids() );
    }

    /**
     * Clear all items from the comparison list.
     *
     * @return array Result with success status.
     */
    public function clear() {
        $this->save_compare_list( array() );
        return array(
            'success'     => true,
            'message'     => __( 'Comparison list cleared.', 'ggm-commerce' ),
            'count'       => 0,
            'product_ids' => array(),
        );
    }

    /**
     * Get all comparison items with product data.
     *
     * @return array Comparison items with product details.
     */
    public function get_items() {
        $product_ids = $this->get_product_ids();

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

        global $wpdb;

        $products_table = $wpdb->prefix . 'ggmc_products';
        $placeholders   = implode( ', ', array_fill( 0, count( $product_ids ), '%d' ) );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
        $products = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT id, name, slug, sku, short_description, description, price, sale_price,
                        stock, stock_status, weight, length, width, height, image_id,
                        average_rating, rating_count, product_type
                FROM {$products_table}
                WHERE id IN ({$placeholders})
                AND (status = 'active' OR status IS NULL)",
                ...$product_ids
            )
        );

        // Index products by ID for ordering.
        $indexed_products = array();
        foreach ( $products as $product ) {
            $indexed_products[ $product->id ] = $product;
        }

        // Return in original order and add additional data.
        $ordered_products = array();
        foreach ( $product_ids as $id ) {
            if ( isset( $indexed_products[ $id ] ) ) {
                $product = $indexed_products[ $id ];

                // Add image URL.
                $product->image_url = '';
                if ( $product->image_id ) {
                    $image_url = wp_get_attachment_image_url( $product->image_id, 'medium' );
                    if ( $image_url ) {
                        $product->image_url = $image_url;
                    }
                }

                // Calculate effective price.
                $product->effective_price = $product->sale_price && $product->sale_price > 0
                    ? $product->sale_price
                    : $product->price;

                // Format dimensions.
                $product->dimensions = $this->format_dimensions( $product );

                // Get categories.
                $product->categories = $this->get_product_categories( $product->id );

                // Get tags.
                $product->tags = $this->get_product_tags( $product->id );

                // Get product URL.
                $product->url = $this->get_product_url( $product );

                // Get custom attributes if the feature is activated.
                $product->custom_attributes = $this->get_product_custom_attributes( $product->id );

                // Get kit components if this is a kit product.
                $product->kit_components = $this->get_product_kit_components( $product->id, $product->product_type );

                $ordered_products[] = $product;
            }
        }

        return $ordered_products;
    }

    /**
     * Get available comparison fields based on activated premium components.
     *
     * @return array Available fields with labels and premium status.
     */
    public function get_available_fields() {
        $license = class_exists( 'GGM_Commerce_License' ) ? \GGM_Commerce_License::instance() : null;

        $fields = array(
            'image' => array(
                'label'   => __( 'Image', 'ggm-commerce' ),
                'premium' => false,
            ),
            'name' => array(
                'label'   => __( 'Name', 'ggm-commerce' ),
                'premium' => false,
            ),
            'price' => array(
                'label'   => __( 'Price', 'ggm-commerce' ),
                'premium' => false,
            ),
            'stock' => array(
                'label'   => __( 'Stock Status', 'ggm-commerce' ),
                'premium' => false,
            ),
            'sku' => array(
                'label'   => __( 'SKU', 'ggm-commerce' ),
                'premium' => false,
            ),
            'description' => array(
                'label'   => __( 'Description', 'ggm-commerce' ),
                'premium' => false,
            ),
            'categories' => array(
                'label'   => __( 'Categories', 'ggm-commerce' ),
                'premium' => false,
            ),
            'tags' => array(
                'label'   => __( 'Tags', 'ggm-commerce' ),
                'premium' => false,
            ),
            'rating' => array(
                'label'   => __( 'Rating', 'ggm-commerce' ),
                'premium' => false,
            ),
            'weight' => array(
                'label'   => __( 'Weight', 'ggm-commerce' ),
                'premium' => false,
            ),
            'dimensions' => array(
                'label'   => __( 'Dimensions', 'ggm-commerce' ),
                'premium' => false,
            ),
            'add_to_cart' => array(
                'label'   => __( 'Add to Cart', 'ggm-commerce' ),
                'premium' => false,
            ),
            'custom_attributes' => array(
                'label'    => __( 'Custom Attributes', 'ggm-commerce' ),
                'premium'  => true,
                'requires' => 'custom-attributes',
            ),
            'barcode' => array(
                'label'    => __( 'Barcode', 'ggm-commerce' ),
                'premium'  => true,
                'requires' => 'barcode',
            ),
            'kit_contents' => array(
                'label'    => __( 'Kit Contents', 'ggm-commerce' ),
                'premium'  => true,
                'requires' => 'product-kits',
            ),
        );

        // Filter out premium fields whose component isn't activated.
        if ( $license ) {
            foreach ( $fields as $key => $field ) {
                if ( ! empty( $field['premium'] ) && ! empty( $field['requires'] ) ) {
                    if ( ! $license->is_widget_activated( $field['requires'] ) ) {
                        unset( $fields[ $key ] );
                    }
                }
            }
        }

        return $fields;
    }

    /**
     * Get product categories.
     *
     * @param int $product_id Product ID.
     * @return array Category names.
     */
    private function get_product_categories( $product_id ) {
        global $wpdb;

        $categories_table = $wpdb->prefix . 'ggmc_categories';
        $pivot_table      = $wpdb->prefix . 'ggmc_product_categories';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $categories = $wpdb->get_col(
            $wpdb->prepare(
                "SELECT c.name FROM {$categories_table} c
                INNER JOIN {$pivot_table} pc ON c.id = pc.category_id
                WHERE pc.product_id = %d
                ORDER BY c.name ASC",
                $product_id
            )
        );

        return $categories;
    }

    /**
     * Get product tags.
     *
     * @param int $product_id Product ID.
     * @return array Tag names.
     */
    private function get_product_tags( $product_id ) {
        global $wpdb;

        $tags_table  = $wpdb->prefix . 'ggmc_tags';
        $pivot_table = $wpdb->prefix . 'ggmc_product_tags';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $tags = $wpdb->get_col(
            $wpdb->prepare(
                "SELECT t.name FROM {$tags_table} t
                INNER JOIN {$pivot_table} pt ON t.id = pt.tag_id
                WHERE pt.product_id = %d
                ORDER BY t.name ASC",
                $product_id
            )
        );

        return $tags;
    }

    /**
     * Format product dimensions.
     *
     * @param object $product Product object.
     * @return string Formatted dimensions or empty string.
     */
    private function format_dimensions( $product ) {
        $dimensions = array();

        if ( ! empty( $product->length ) && $product->length > 0 ) {
            $dimensions[] = $product->length;
        }
        if ( ! empty( $product->width ) && $product->width > 0 ) {
            $dimensions[] = $product->width;
        }
        if ( ! empty( $product->height ) && $product->height > 0 ) {
            $dimensions[] = $product->height;
        }

        if ( empty( $dimensions ) ) {
            return '';
        }

        return implode( ' × ', $dimensions ) . ' cm';
    }

    /**
     * Get product URL.
     *
     * @param object $product Product object.
     * @return string Product details URL.
     */
    private function get_product_url( $product ) {
        $product_details_page_id = get_option( 'ggm_commerce_product_details_page_id' );

        if ( ! $product_details_page_id ) {
            return '#';
        }

        $base_url = get_permalink( $product_details_page_id );

        if ( ! $base_url ) {
            return '#';
        }

        if ( ! empty( $product->slug ) ) {
            return trailingslashit( $base_url ) . sanitize_title( $product->slug ) . '/';
        }

        return add_query_arg( 'id', $product->id, $base_url );
    }

    /**
     * Get custom attributes for a product.
     *
     * @param int $product_id Product ID.
     * @return array Custom attributes with name and value.
     */
    private function get_product_custom_attributes( $product_id ) {
        // Check if custom attributes feature is activated.
        if ( ! class_exists( 'GGM_Commerce_License' ) ) {
            return array();
        }

        $license = \GGM_Commerce_License::instance();
        if ( ! $license->is_widget_activated( 'custom-attributes' ) ) {
            return array();
        }

        // Get attributes manager using singleton pattern.
        if ( ! class_exists( 'GGM_Commerce_Attributes' ) ) {
            return array();
        }

        $attributes_manager = \GGM_Commerce_Attributes::get_instance();
        return $attributes_manager->get_product_attributes( $product_id );
    }

    /**
     * Get kit components for a product.
     *
     * @param int    $product_id   Product ID.
     * @param string $product_type Product type.
     * @return array Kit components with product details.
     */
    private function get_product_kit_components( $product_id, $product_type ) {
        // Only fetch for kit/build products.
        if ( ! in_array( $product_type, array( 'kit', 'build' ), true ) ) {
            return array();
        }

        // Check if kits feature is activated.
        if ( ! class_exists( 'GGM_Commerce_License' ) ) {
            return array();
        }

        $license = \GGM_Commerce_License::instance();
        if ( ! $license->is_widget_activated( 'product-kits' ) ) {
            return array();
        }

        // Get kits manager using singleton pattern.
        if ( ! class_exists( 'GGM_Commerce_Kits' ) ) {
            return array();
        }

        $kits_manager = \GGM_Commerce_Kits::get_instance();
        return $kits_manager->get_components_by_product_id( $product_id );
    }

    /**
     * Check if a product exists in the database.
     *
     * @param int $product_id Product ID.
     * @return bool
     */
    private function product_exists( $product_id ) {
        global $wpdb;

        $products_table = $wpdb->prefix . 'ggmc_products';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $exists = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT id FROM {$products_table} WHERE id = %d",
                $product_id
            )
        );

        return (bool) $exists;
    }

    /**
     * Verify AJAX nonce.
     *
     * @return bool True if nonce is valid.
     */
    private function verify_ajax_nonce() {
        $nonce = '';
        if ( isset( $_POST['nonce'] ) ) {
            $nonce = sanitize_text_field( wp_unslash( $_POST['nonce'] ) );
        } elseif ( isset( $_GET['nonce'] ) ) {
            $nonce = sanitize_text_field( wp_unslash( $_GET['nonce'] ) );
        }

        return wp_verify_nonce( $nonce, 'ggm_commerce_compare_nonce' );
    }

    /**
     * AJAX: Add product to comparison.
     */
    public function ajax_add_to_compare() {
        if ( ! $this->verify_ajax_nonce() ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
        $result     = $this->add_item( $product_id );

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

    /**
     * AJAX: Remove product from comparison.
     */
    public function ajax_remove_from_compare() {
        if ( ! $this->verify_ajax_nonce() ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
        $result     = $this->remove_item( $product_id );

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

    /**
     * AJAX: Toggle product in comparison.
     */
    public function ajax_toggle_compare() {
        if ( ! $this->verify_ajax_nonce() ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
        $result     = $this->toggle_item( $product_id );

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

    /**
     * AJAX: Get comparison data.
     */
    public function ajax_get_compare() {
        if ( ! $this->verify_ajax_nonce() ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $include_products = isset( $_POST['include_products'] ) && $_POST['include_products'];

        $response = array(
            'success'     => true,
            'count'       => $this->get_count(),
            'product_ids' => $this->get_product_ids(),
            'max'         => self::get_max_products(),
        );

        if ( $include_products ) {
            $response['products'] = $this->get_items();
        }

        wp_send_json_success( $response );
    }

    /**
     * AJAX: Clear comparison.
     */
    public function ajax_clear_compare() {
        if ( ! $this->verify_ajax_nonce() ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'ggm-commerce' ) ) );
        }

        $result = $this->clear();
        wp_send_json_success( $result );
    }

    /**
     * Get the comparison page URL.
     *
     * @return string Comparison page URL or empty string.
     */
    public function get_comparison_page_url() {
        $page_id = get_option( 'ggm_commerce_comparison_page_id' );

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

        return get_permalink( $page_id );
    }
}

/**
 * Get the Product Comparison instance.
 *
 * @return GGM_Commerce_Product_Comparison
 */
function ggm_commerce_product_comparison() {
    return GGM_Commerce_Product_Comparison::instance();
}

// Initialize the comparison class.
ggm_commerce_product_comparison();
