<?php
/**
 * AJAX Handlers for Paapi Product Search for Amazon
 *
 * Handles all AJAX requests for the plugin including infinite scroll
 * and autocomplete functionality.
 */

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

/**
 * AJAX handler for infinite scroll (load more products)
 */
function psfa_ajax_load_more() {
    check_ajax_referer( 'psfa_ajax_nonce', 'nonce' );

    // Centralized, DRY parameter parsing.
    require_once PSFA_PLUGIN_DIR . 'src/core/search/functions.php';
    $search_params = psfa_get_search_params();

    $q                  = $search_params['query'];
    $cat                = $search_params['category'];
    $page               = $search_params['page'];
    $min                = $search_params['min_price'];
    $max                = $search_params['max_price'];
    $filter_brand       = $search_params['brand'];
    $sort               = $search_params['sort'];
    $condition          = $search_params['condition'];
    $merchant           = $search_params['merchant'];
    $availability       = $search_params['availability'];
    // Premium filters
    $has_deal           = $search_params['has_deal'];
    $min_rating         = $search_params['min_rating'];
    $min_saving_percent = $search_params['min_saving_percent'];
    
    // Require at least query or category - both cannot be empty
    // Even during pagination, we need the original search context
    if ( empty( $q ) && empty( $cat ) ) {
        wp_send_json_error( array(
            'error' => 'Search query or category required. Original search parameters must be preserved during pagination.',
        ) );
    }
    
    // Check license limits
    require_once PSFA_PLUGIN_DIR . 'src/core/search/view-helpers.php';
    $max_pages = psfa_get_max_pages();
    
    // Check if category is available
    if ( !empty( $cat ) && !psfa_is_category_available( $cat ) ) {
        $upgrade_url = 'https://paapiplugin.com/pricing/#plans';
        wp_send_json_error( array(
            'error' => psfa_render_category_upgrade_notice($upgrade_url),
        ) );
    }

    // For live PA-API calls, MinPrice/MaxPrice are not supported by PA-API v5
    // so price filtering is applied client-side after the API call.
    // In mock mode, we pass the actual price filters so that sorting happens
    // on already-filtered data, ensuring correct sort order across pages.
    $api_min = $min;
    $api_max = $max;

    // For "OutOfStockOnly" filter, we need to request IncludeOutOfStock from PA-API
    // and then filter client-side to show only out of stock items
    // For empty or 'Available', pass it through (PA-API defaults to Available)
    $api_availability = ($availability === 'OutOfStockOnly') ? 'IncludeOutOfStock' : $availability;
    if (empty($api_availability)) {
        $api_availability = 'Available'; // Explicit default
    }
    
    // Preserve original sort for cache metadata (effective sort may be empty for price sorts).
    $GLOBALS['psfa_original_sort'] = $sort;
    // Get effective sort - skip price sorts for OAuth (API doesn't honor them)
    require_once PSFA_PLUGIN_DIR . 'src/core/search/helpers.php';
    $effective_sort = psfa_get_effective_sort($sort, $min, $max);
    
    $results = psfa_amazon_search_products(
        $q,
        $cat,
        $api_min,
        $api_max,
        $page,
        $effective_sort,
        $filter_brand,
        $condition,
        $merchant,
        $has_deal,
        $min_rating,
        $min_saving_percent,
        $api_availability
    );
    
    if ( isset( $results['error'] ) ) {
        // Log detailed error for debugging
        $error_message = $results['error'];
        if ( isset( $results['details'] ) ) {
            $error_message .= ' - Details: ' . json_encode( $results['details'] );
        }
        wp_send_json_error( array(
            'error' => $error_message,
        ) );
    }
    
    // Check if Items exists and is a valid array
    if ( !isset( $results['SearchResult']['Items'] ) || !is_array( $results['SearchResult']['Items'] ) ) {
        wp_send_json_success( array(
            'items'    => array(),
            'has_more' => false,
        ) );
    }
    
    $all_items = $results['SearchResult']['Items'];
    // Items are already filtered by PA-API server-side (Brand, Condition, Merchant)
    $total_results = $results['SearchResult']['TotalResultCount'] ?? 0;
    $items_per_page = 10;
    $unfiltered_count = count( $all_items );
    
    // Apply price filtering client-side for live PA-API (not supported by PA-API v5)
    // In mock mode, price filtering is already done in search-core.php before sorting/pagination
    if ( defined( 'PSFA_MOCK_MODE' ) && PSFA_MOCK_MODE ) {
        $filtered_items = $all_items; // Already filtered in search-core.php
    } else {
        $filtered_items = psfa_filter_products_by_price( $all_items, $min, $max );
    }
    
    // Apply Condition filtering client-side for live PA-API
    // PA-API Condition is a hint, not a strict filter - enforce it here
    if ( !empty( $condition ) && function_exists( 'psfa_filter_products_by_condition' ) ) {
        $filtered_items = psfa_filter_products_by_condition( $filtered_items, $condition );
    }
    
    // Apply Merchant filtering client-side for live PA-API
    // PA-API Merchant is a hint, not a strict filter - enforce it here
    if ( !empty( $merchant ) && function_exists( 'psfa_filter_products_by_merchant' ) ) {
        $filtered_items = psfa_filter_products_by_merchant( $filtered_items, $merchant );
    }
    
    // Apply Availability filtering client-side for "Out of Stock Only"
    // PA-API only supports Available or IncludeOutOfStock, not OutOfStockOnly
    if ( $availability === 'OutOfStockOnly' && function_exists( 'psfa_filter_products_by_availability' ) ) {
        $filtered_items = psfa_filter_products_by_availability( $filtered_items, 'OutOfStockOnly' );
    }
    
    
    
    // Apply client-side sorting if needed (Brand+Sort, PriceFilter+PriceSort, HasDeal+Sort, MinSavingPercent+PriceSort)
    if ( function_exists( 'psfa_needs_client_sort' ) && psfa_needs_client_sort( $filter_brand, $sort, $min, $max, $has_deal, $min_saving_percent ) ) {
        $filtered_items = psfa_sort_items( $filtered_items, $sort );
    }
    
    // Format items for JSON response
    require_once PSFA_PLUGIN_DIR . 'src/core/shared/customization-helpers.php';
    require_once PSFA_PLUGIN_DIR . 'src/core/api/class-offer-data-extractor.php';
    $buy_button_icon = plugins_url( 'src/assets/img/amazon-logo.svg', PSFA_PLUGIN_DIR . 'paapi-product-search-for-amazon.php' );
    
    // Use offer data extractor for single source of truth (V2 only)
    $extractor = psfa_get_offer_extractor();
    
    $formatted_items = array();
    foreach ( $filtered_items as $item ) {
        $formatted_items[] = array(
            'asin'          => $item['ASIN'] ?? '',
            'title'         => $item['ItemInfo']['Title']['DisplayValue'] ?? '(No Title)',
            'url'           => $item['DetailPageURL'] ?? '#',
            'img'           => $item['Images']['Primary']['Large']['URL'] ?? '',
            'brand'         => $item['ItemInfo']['ByLineInfo']['Brand']['DisplayValue'] ?? '',
            'price'         => $extractor->get_price_display( $item ),
            'buyButtonIcon' => $buy_button_icon,
            // V2 Premium badge data
            'dealBadge'         => $extractor->get_deal_badge( $item ),
            'dealCountdown'     => $extractor->get_deal_countdown( $item ),
            'isPrimeExclusive'  => $extractor->is_prime_exclusive_deal( $item ),
            'isStockScarce'     => $extractor->is_stock_scarce( $item ),
            'salesRank'         => $item['BrowseNodeInfo']['WebsiteSalesRank']['SalesRank'] ?? 0,
            'savingBasis'       => $extractor->get_original_price_display( $item ),
            'savingPercent'     => $extractor->get_savings_percent( $item ) ?? 0,
            'hasDeal'           => $extractor->has_deal( $item ),
            // Availability data for client-side filtering
            'availabilityType'    => $extractor->get_availability_type( $item ) ?: 'Now',
            'availabilityMessage' => $extractor->get_availability_message( $item ),
        );
    }
    
    // Determine if more pages exist
    // IMPORTANT: When price filtering is applied client-side, we need to continue fetching
    // as long as the API returns items, even if price filtering results in 0 items on some pages
    $has_more = false;
    $formatted_count = count( $formatted_items );
    
    // CRITICAL: Amazon PA-API v5 only supports ItemPage 1-10 (maximum 10 pages)
    // This is a hard limit from Amazon, regardless of premium status
    $amazon_max_page = 10;
    if ( $page >= $amazon_max_page ) {
        wp_send_json_success( array(
            'items'    => $formatted_items,
            'has_more' => false,
        ) );
        return;
    }
    
    // AGGRESSIVE CHECK: Stop on max pages (5 for free, 999 for premium)
    // But also respect Amazon's 10-page limit
    $effective_max_pages = min( $max_pages, $amazon_max_page );
    if ( $page >= $effective_max_pages ) {
        $upgrade_notice = '';
        // Only show upgrade notice for free users when NOT in mock mode
        if ( !psfa_is_premium() && !( defined( 'PSFA_MOCK_MODE' ) && PSFA_MOCK_MODE ) ) {
            $upgrade_url = 'https://paapiplugin.com/pricing/#plans';
            $upgrade_notice = 'You\'ve reached the free limit of 5 pages. <a href="' . esc_url( $upgrade_url ) . '" target="_blank">Upgrade to Premium</a> for unlimited pagination.';
        }
        wp_send_json_success( array(
            'items'          => $formatted_items,
            'has_more'       => false,
            'upgrade_notice' => $upgrade_notice,
        ) );
        return;
    }
    
    // Base decision on unfiltered items from API, not filtered items
    // This is critical when price filtering is applied client-side
    // But never allow has_more to be true if we're at or past page 10
    if ( $unfiltered_count === 0 ) {
        // API returned 0 items - definitely no more pages
        $has_more = false;
    } elseif ( $unfiltered_count >= $items_per_page ) {
        // Got a full page from API (10 items) - there might be more
        if ( $total_results > 0 ) {
            // Use TotalResultCount to determine if more pages exist
            $total_pages = ceil( $total_results / $items_per_page );
            // Cap at Amazon's maximum of 10 pages
            $total_pages = min( $total_pages, $amazon_max_page );
            $has_more = $page < $total_pages;
        } else {
            // No TotalResultCount, but got full page - assume more pages exist
            // But never beyond page 10
            $has_more = $page < $amazon_max_page;
        }
    } elseif ( $total_results > 0 && $unfiltered_count > 0 ) {
        // Partial page with TotalResultCount
        $total_pages = ceil( $total_results / $items_per_page );
        // Cap at Amazon's maximum of 10 pages
        $total_pages = min( $total_pages, $amazon_max_page );
        $has_more = $page < $total_pages;
    } elseif ( $unfiltered_count > 0 && $unfiltered_count < $items_per_page ) {
        // Partial page without TotalResultCount - this is likely the last page
        $has_more = false;
    }
    
    // Final safety check: Never allow has_more beyond page 10
    if ( $page >= $amazon_max_page ) {
        $has_more = false;
    }
    
    // Safety check: If we've fetched many pages with 0 filtered results, stop to prevent infinite loops
    // Only apply this if we've fetched at least 10 pages and got 0 items on the last 3 consecutive pages
    // (This is handled by the sequential page fetching logic in JavaScript, so we can be more lenient here)
    // For now, we'll continue as long as API returns items and we haven't hit max pages
    
    // Extract unique brands from results for filter dropdown
    $brands = array();
    foreach ( $formatted_items as $item ) {
        if ( !empty( $item['brand'] ) && !in_array( $item['brand'], $brands, true ) ) {
            $brands[] = $item['brand'];
        }
    }
    sort( $brands );
    
    wp_send_json_success( array(
        'items'          => $formatted_items,
        'has_more'       => $has_more,
        'filter_options' => array(
            'brands' => $brands,
        ),
    ) );
}

/**
 * AJAX handler for autocomplete
 */
function psfa_ajax_autocomplete() {
    check_ajax_referer( 'psfa_ajax_nonce', 'nonce' );
    
    $query = '';
    if ( isset( $_GET['q'] ) ) {
        $query = sanitize_text_field( wp_unslash( $_GET['q'] ) );
    }
    
    if ( strlen( $query ) < 2 ) {
        wp_send_json_success( array(
            'suggestions' => array(),
        ) );
    }
    
    // Proxy Amazon's autocomplete API server-side to bypass CORS
    // Amazon blocks direct browser requests, so we proxy through our server
    // Try simpler endpoint first
    $amazon_autocomplete_url = 'https://completion.amazon.com/api/2017/suggestions?limit=11&prefix=' . urlencode( $query ) . '&suggestion-type=KEYWORD&alias=aps&lop=en_US&mid=ATVPDKIKX0DER';
    
    // WordPress HTTP API request
    $request_args = array(
        'timeout'     => 3,
        'sslverify'   => true,
        'redirection' => 5,
        'user-agent'  => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'headers'     => array(
            'Accept'          => 'application/json',
            'Accept-Language' => 'en-US,en;q=0.9',
            'Origin'          => 'https://www.amazon.com',
            'Referer'         => 'https://www.amazon.com/',
        ),
    );
    
    $response = wp_remote_get( $amazon_autocomplete_url, $request_args );
    $suggestions = array();
    
    // Check for WordPress HTTP API errors
    if ( is_wp_error( $response ) ) {
        wp_send_json_success( array(
            'suggestions' => array(),
        ) );
        return;
    }
    
    $http_code = wp_remote_retrieve_response_code( $response );
    $response_body = wp_remote_retrieve_body( $response );
    
    if ( $http_code === 200 && !empty( $response_body ) ) {
        $data = json_decode( $response_body, true );
        $json_error = json_last_error();
        
        if ( $json_error === JSON_ERROR_NONE && is_array( $data ) ) {
            // Try multiple response formats
            // Format 1: {"suggestions": [{"value": "tomatoes"}, ...]}
            if ( isset( $data['suggestions'] ) && is_array( $data['suggestions'] ) ) {
                foreach ( $data['suggestions'] as $item ) {
                    if ( isset( $item['value'] ) && is_string( $item['value'] ) && !empty( $item['value'] ) ) {
                        $suggestions[] = $item['value'];
                    } elseif ( is_string( $item ) && !empty( $item ) ) {
                        $suggestions[] = $item;
                    } elseif ( is_array( $item ) && isset( $item['suggestion'] ) ) {
                        $suggestions[] = $item['suggestion'];
                    }
                }
            } elseif ( !empty( $data ) && is_string( $data[0] ?? null ) ) {
                foreach ( $data as $item ) {
                    if ( is_string( $item ) && !empty( $item ) ) {
                        $suggestions[] = $item;
                    }
                }
            } elseif ( isset( $data[0] ) && is_array( $data[0] ) ) {
                foreach ( $data as $item ) {
                    if ( is_array( $item ) ) {
                        if ( isset( $item['value'] ) ) {
                            $suggestions[] = $item['value'];
                        } elseif ( isset( $item['suggestion'] ) ) {
                            $suggestions[] = $item['suggestion'];
                        } elseif ( isset( $item['text'] ) ) {
                            $suggestions[] = $item['text'];
                        } elseif ( count( $item ) === 1 && is_string( $item[0] ?? null ) ) {
                            $suggestions[] = $item[0];
                        }
                    }
                }
            }
        }
    }
    
    wp_send_json_success( array(
        'suggestions' => array_slice( $suggestions, 0, 8 ),
    ) );
}

