<?php

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

class AIEO_DMM_Swatches_Ajax {

    
    private static $instance = null;

    public static function instance() {
        if ( self::$instance === null ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        
        
        
        
        
        
        
        
        
        $actions = array(
            'batch_add_to_cart'     => 'ajax_batch_add_to_cart',
            'quick_add_to_cart'     => 'ajax_quick_add_to_cart',
            
            
            'sync_cart'             => 'ajax_sync_cart',
            
            
            'get_cart_variations'   => 'ajax_get_cart_variations',
            'get_all_variations'    => 'ajax_get_all_variations',
            'get_modal_variations'  => 'ajax_get_modal_variations',
            
            
            'refresh_nonce'         => 'ajax_refresh_nonce',
        );

        foreach ( $actions as $suffix => $callback ) {
            $new = 'aieo_swatch_' . $suffix;
            add_action( 'wp_ajax_'        . $new, array( $this, $callback ) );
            add_action( 'wp_ajax_nopriv_' . $new, array( $this, $callback ) );

            
            
            
            
            
            
            
            
            
            $legacy = 'om_swatch_' . $suffix;
            add_action( 'wp_ajax_'        . $legacy, array( $this, $callback ) );
            add_action( 'wp_ajax_nopriv_' . $legacy, array( $this, $callback ) );
        }

        
        
        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_nonce_refresh' ), 999 );
    }

    
    public function ajax_refresh_nonce() {
        wp_send_json_success( array( 'nonce' => wp_create_nonce( 'aieo_swatches_frontend' ) ) );
    }

    
    public function enqueue_nonce_refresh() {
        if ( is_admin() ) { return; }
        if ( ! wp_script_is( 'aieo-swatches', 'enqueued' ) && ! wp_script_is( 'aieo-swatches', 'registered' ) ) { return; }
        $js = "(function(){var s=window.omSwatchSettings;if(!s)return;"
            . "var u=(s.ajax_url)||(window.omProductSwatches&&window.omProductSwatches.ajaxUrl)||'/wp-admin/admin-ajax.php';"
            . "try{fetch(u+(u.indexOf('?')>-1?'&':'?')+'action=aieo_swatch_refresh_nonce',{credentials:'same-origin'})"
            . ".then(function(r){return r.ok?r.json():null;})"
            . ".then(function(d){if(d&&d.success&&d.data&&d.data.nonce){window.omSwatchSettings.security=d.data.nonce;"
            . "if(window.omProductSwatches)window.omProductSwatches.nonce=d.data.nonce;"
            . "if(window.aieoSwatches)window.aieoSwatches.nonce=d.data.nonce;}}).catch(function(){});}catch(e){}})();";
        wp_add_inline_script( 'aieo-swatches', $js, 'after' );
    }

    
    public function ajax_batch_add_to_cart() {
        $this->verify_nonce();

        if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
            wp_send_json_error( array( 'message' => 'Cart unavailable.' ) );
        }

        $items = isset( $_POST['variations'] ) && is_array( $_POST['variations'] )
            ? wp_unslash( $_POST['variations'] )
            : array();

        if ( empty( $items ) ) {
            wp_send_json_error( array( 'message' => 'No variations supplied.' ) );
        }

        $added = 0;

        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) { continue; }
            $vid = isset( $item['variation_id'] ) ? absint( $item['variation_id'] ) : 0;
            $qty = isset( $item['quantity'] )     ? max( 1, absint( $item['quantity'] ) ) : 1;
            if ( $vid <= 0 ) { continue; }

            $pid = (int) wp_get_post_parent_id( $vid );
            if ( $pid <= 0 ) { continue; }

            $attributes = $this->attributes_for_variation( $vid );
            
            
            
            $key = WC()->cart->add_to_cart( $pid, $qty, $vid, $attributes );
            if ( $key ) { $added++; }
        }

        if ( $added === 0 ) {
            wp_send_json_error( array( 'message' => 'Nothing added to cart.' ) );
        }

        $cart = WC()->cart;
        wp_send_json_success( array(
            'added'      => $added,
            'cart_count' => $cart->get_cart_contents_count(),
            'cart_total' => $cart->get_cart_total(),
            'cart_hash'  => $cart->get_cart_hash(),
            'fragments'  => $this->get_fragments(),
        ) );
    }

    
    public function ajax_quick_add_to_cart() {
        $this->verify_nonce();

        if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
            wp_send_json_error( array( 'message' => 'Cart unavailable.' ) );
        }

        $variation_id = isset( $_POST['variation_id'] ) ? absint( $_POST['variation_id'] ) : 0;
        $quantity     = isset( $_POST['quantity'] )     ? max( 1, absint( $_POST['quantity'] ) ) : 1;

        if ( $variation_id <= 0 ) {
            wp_send_json_error( array( 'message' => 'Invalid variation ID.' ) );
        }

        $variation = wc_get_product( $variation_id );
        if ( ! $variation || ! $variation->is_type( 'variation' ) ) {
            wp_send_json_error( array( 'message' => 'Invalid variation.' ) );
        }
        if ( ! $variation->is_purchasable() ) {
            wp_send_json_error( array( 'message' => 'This product cannot be purchased.' ) );
        }
        if ( ! $variation->is_in_stock() ) {
            wp_send_json_error( array( 'message' => 'This variation is out of stock.' ) );
        }

        $product_id = (int) $variation->get_parent_id();
        $attributes = $variation->get_variation_attributes();

        $key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $attributes );

        if ( ! $key ) {
            wp_send_json_error( array( 'message' => 'Could not add to cart.' ) );
        }

        ob_start();
        if ( function_exists( 'woocommerce_mini_cart' ) ) { woocommerce_mini_cart(); }
        $mini_cart = ob_get_clean();

        $cart = WC()->cart;
        wp_send_json_success( array(
            'message'       => 'Added to cart!',
            'cart_item_key' => $key,
            'cart_hash'     => $cart->get_cart_hash(),
            'cart_total'    => $cart->get_cart_total(),
            'cart_count'    => $cart->get_cart_contents_count(),
            'fragments'     => apply_filters( 'woocommerce_add_to_cart_fragments', array(
                'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>',
            ) ),
        ) );
    }

    
    public function ajax_sync_cart() {
        $this->verify_nonce();

        if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
            wp_send_json_error( array( 'message' => 'Cart unavailable.' ) );
        }

        $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
        $items_raw  = isset( $_POST['items'] ) ? wp_unslash( (string) $_POST['items'] ) : '';
        $items      = json_decode( $items_raw, true );
        if ( ! is_array( $items ) || empty( $items ) ) {
            wp_send_json_error( array( 'message' => 'No items to sync.' ) );
        }

        
        
        $variation_ids = array();
        foreach ( $items as $item ) {
            $vid = isset( $item['variation_id'] ) ? absint( $item['variation_id'] ) : 0;
            if ( $vid > 0 ) { $variation_ids[] = $vid; }
        }
        if ( ! empty( $variation_ids ) ) {
            get_posts( array(
                'post_type'      => 'product_variation',
                'post__in'       => array_values( array_unique( $variation_ids ) ),
                'posts_per_page' => count( $variation_ids ),
                'post_status'    => 'publish',
                'fields'         => 'ids',
            ) );
        }

        $synced_items = array();
        $errors       = array();

        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) { continue; }
            $variation_id  = isset( $item['variation_id'] )  ? absint( $item['variation_id'] )            : 0;
            $quantity      = isset( $item['quantity'] )      ? absint( $item['quantity'] )                : 0;
            $cart_item_key = isset( $item['cart_item_key'] ) ? sanitize_text_field( $item['cart_item_key'] ) : '';
            if ( $variation_id === 0 ) { continue; }

            $variation = wc_get_product( $variation_id );

            
            if ( $cart_item_key !== '' && $quantity === 0 ) {
                $removed = WC()->cart->remove_cart_item( $cart_item_key );
                if ( $removed ) {
                    $synced_items[] = array( 'variation_id' => $variation_id, 'action' => 'removed' );
                } else {
                    $errors[] = sprintf( 'Could not remove variation #%d.', $variation_id );
                }
                continue;
            }

            
            if ( $cart_item_key !== '' && $quantity > 0 ) {
                $updated = WC()->cart->set_quantity( $cart_item_key, $quantity );
                if ( $updated ) {
                    $synced_items[] = array(
                        'variation_id'  => $variation_id,
                        'quantity'      => $quantity,
                        'name'          => $variation ? $variation->get_name() : '',
                        'cart_item_key' => $cart_item_key,
                        'action'        => 'updated',
                    );
                } else {
                    $errors[] = sprintf( 'Could not update variation #%d.', $variation_id );
                }
                continue;
            }

            
            if ( $cart_item_key === '' && $quantity > 0 ) {
                if ( ! $variation || ! $variation->is_purchasable() ) {
                    $errors[] = sprintf( 'Variation #%d is not purchasable.', $variation_id );
                    continue;
                }
                if ( ! $variation->is_in_stock() && ! $variation->backorders_allowed() ) {
                    $errors[] = sprintf( '%s is out of stock.', $variation->get_name() );
                    continue;
                }
                $parent_id = $product_id ? $product_id : (int) $variation->get_parent_id();
                $attrs     = $this->attributes_for_variation( $variation_id );
                $new_key   = WC()->cart->add_to_cart( $parent_id, $quantity, $variation_id, $attrs );
                if ( $new_key ) {
                    $synced_items[] = array(
                        'variation_id'  => $variation_id,
                        'quantity'      => $quantity,
                        'name'          => $variation->get_name(),
                        'cart_item_key' => $new_key,
                        'action'        => 'added',
                    );
                } else {
                    $errors[] = sprintf( 'Could not add %s to cart.', $variation ? $variation->get_name() : "#$variation_id" );
                }
            }
        }

        
        $product_cart_state = array();
        foreach ( WC()->cart->get_cart() as $key => $ci ) {
            $vid = isset( $ci['variation_id'] ) ? (int) $ci['variation_id'] : 0;
            $pid = isset( $ci['product_id'] )   ? (int) $ci['product_id']   : 0;
            if ( $vid === 0 ) { continue; }
            if ( $product_id > 0 && $pid !== $product_id ) { continue; }
            $product_cart_state[ $vid ] = array(
                'qty'           => (int) ( $ci['quantity'] ?? 0 ),
                'cart_item_key' => (string) $key,
            );
        }

        ob_start();
        if ( function_exists( 'woocommerce_mini_cart' ) ) { woocommerce_mini_cart(); }
        $mini_cart = ob_get_clean();

        $cart = WC()->cart;
        wp_send_json_success( array(
            'message'            => 'Cart updated.',
            'synced_items'       => $synced_items,
            'product_cart_state' => $product_cart_state,
            'errors'             => $errors,
            'cart_hash'          => $cart->get_cart_hash(),
            'cart_total'         => $cart->get_cart_total(),
            'cart_count'         => $cart->get_cart_contents_count(),
            'fragments'          => apply_filters( 'woocommerce_add_to_cart_fragments', array(
                'div.widget_shopping_cart_content' => '<div class="widget_shopping_cart_content">' . $mini_cart . '</div>',
            ) ),
        ) );
    }

    
    public function ajax_get_cart_variations() {
        $this->verify_nonce();

        if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
            wp_send_json_success( array( 'variations' => (object) array() ) );
        }

        $out = array();
        foreach ( WC()->cart->get_cart() as $cart_item ) {
            $vid = isset( $cart_item['variation_id'] ) ? (int) $cart_item['variation_id'] : 0;
            if ( $vid > 0 ) {
                $out[ $vid ] = ( $out[ $vid ] ?? 0 ) + (int) ( $cart_item['quantity'] ?? 0 );
            }
        }
        wp_send_json_success( array( 'variations' => $out ) );
    }

    
    public function ajax_get_all_variations() {
        $this->verify_nonce();

        $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
        if ( $product_id <= 0 ) {
            wp_send_json_error( array( 'message' => 'Missing product_id.' ) );
        }

        global $wpdb;
        $table = $wpdb->prefix . 'aieo_dmm_swatches_cache';
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT variations_json, total_available, stored_count
             FROM {$table}
             WHERE product_id = %d AND context = 'single'
             LIMIT 1",
            $product_id
        ), ARRAY_A );

        $variations = array();
        if ( $row ) {
            $decoded = json_decode( (string) $row['variations_json'], true );
            if ( is_array( $decoded ) ) { $variations = $decoded; }
        }

        
        if ( empty( $variations ) ) {
            $product = wc_get_product( $product_id );
            if ( $product && $product->is_type( 'variable' ) ) {
                $runtime = AIEO_DMM_Swatches_Runtime::instance();
                
                $variations = $this->build_fallback_variations( $product );
            }
        }

        wp_send_json_success( array(
            'product_id' => $product_id,
            'variations' => $variations,
            'total'      => count( $variations ),
        ) );
    }

    
    public function ajax_get_modal_variations() {
        $this->verify_nonce();

        $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
        if ( $product_id <= 0 ) {
            wp_send_json_error( array( 'message' => 'Missing product_id.' ) );
        }

        $product = wc_get_product( $product_id );
        if ( ! $product || ! $product->is_type( 'variable' ) ) {
            wp_send_json_error( array( 'message' => 'Invalid product.' ) );
        }

        $image_id   = (int) $product->get_image_id();
        $image_data = $image_id > 0 ? wp_get_attachment_image_src( $image_id, 'thumbnail' ) : false;
        $image_url  = is_array( $image_data ) && ! empty( $image_data[0] )
            ? (string) $image_data[0]
            : (string) wc_placeholder_img_src( 'thumbnail' );

        
        
        
        global $post;
        $orig_post    = $post;
        $orig_product = isset( $GLOBALS['product'] ) ? $GLOBALS['product'] : null;

        $post = get_post( $product_id );
        $GLOBALS['product'] = $product;
        setup_postdata( $post );

        
        
        
        $modal_true = function () { return true; };
        add_filter( 'aieo_product_swatches_modal_context', $modal_true );
        add_filter( 'om_product_swatches_modal_context',   $modal_true );

        $form_html = '';
        try {
            ob_start();
            if ( function_exists( 'woocommerce_variable_add_to_cart' ) ) {
                woocommerce_variable_add_to_cart();
            }
            $form_html = (string) ob_get_clean();
        } finally {
            remove_filter( 'aieo_product_swatches_modal_context', $modal_true );
            remove_filter( 'om_product_swatches_modal_context',   $modal_true );

            $post               = $orig_post;
            $GLOBALS['product'] = $orig_product;
            if ( $orig_post ) {
                setup_postdata( $orig_post );
            } else {
                wp_reset_postdata();
            }
        }

        $total = count( (array) $product->get_children() );

        wp_send_json_success( array(
            'product'   => array(
                'id'        => $product_id,
                'name'      => (string) $product->get_name(),
                'permalink' => (string) $product->get_permalink(),
                'image_url' => $image_url,
            ),
            'form_html' => $form_html,
            'total'     => $total,
        ) );
    }

    

    private function verify_nonce() {
        
        
        
        
        
        
        $nonce_ok = check_ajax_referer( 'aieo_swatches_frontend', 'security', false )
                 || check_ajax_referer( 'aieo_swatches_frontend', 'nonce',    false );
        if ( ! $nonce_ok ) {
            wp_send_json_error( array( 'message' => 'Invalid nonce.' ), 403 );
        }
    }

    
    private function attributes_for_variation( $variation_id ) {
        $variation_id = (int) $variation_id;
        if ( $variation_id <= 0 ) { return array(); }

        $meta = get_post_meta( $variation_id );
        if ( ! is_array( $meta ) ) { return array(); }

        $out = array();
        foreach ( $meta as $k => $v ) {
            if ( strpos( $k, 'attribute_' ) === 0 ) {
                $out[ $k ] = isset( $v[0] ) ? wc_clean( $v[0] ) : '';
            }
        }
        return $out;
    }

    private function get_fragments() {
        if ( ! function_exists( 'WC' ) || ! WC()->cart ) { return array(); }
        
        
        return apply_filters( 'woocommerce_add_to_cart_fragments', array() );
    }

    private function build_fallback_variations( WC_Product $product ) {
        $out = array();
        foreach ( (array) $product->get_children() as $vid ) {
            $meta = get_post_meta( (int) $vid );
            if ( ! is_array( $meta ) ) { continue; }
            $attributes = array();
            foreach ( $meta as $k => $v ) {
                if ( strpos( $k, 'attribute_' ) === 0 ) {
                    $attributes[ $k ] = isset( $v[0] ) ? wc_clean( $v[0] ) : '';
                }
            }
            $stock = isset( $meta['_stock_status'][0] ) ? (string) $meta['_stock_status'][0] : '';
            $out[] = array(
                'variation_id' => (int) $vid,
                'available'    => ( $stock === 'instock' || $stock === 'onbackorder' ),
                'attributes'   => $attributes,
                'stock_status' => $stock,
            );
        }
        return $out;
    }
}
