<?php

/**
 * A1-WooBay - Admin AJAX Handlers
 *
 * @package A1_WooBay
 * @since   0.3.4
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
class A1WooBay_Ajax {
    public function __construct() {
        // Taxonomy / policy loaders (admin UI)
        add_action( 'wp_ajax_a1woobay_search_categories', array($this, 'search_categories') );
        add_action( 'wp_ajax_a1woobay_get_policies', array($this, 'get_policies') );
        // Product listing actions
        add_action( 'wp_ajax_a1woobay_verify_product', array($this, 'verify_product') );
        add_action( 'wp_ajax_a1woobay_push_product', array($this, 'push_product') );
        add_action( 'wp_ajax_a1woobay_revise_product', array($this, 'revise_product') );
        add_action( 'wp_ajax_a1woobay_end_listing', array($this, 'end_listing') );
        add_action( 'wp_ajax_a1woobay_mark_sold', array($this, 'mark_sold') );
        add_action( 'wp_ajax_a1woobay_fetch_ebay_inventory', array($this, 'fetch_ebay_inventory') );
        add_action( 'wp_ajax_a1woobay_adopt_listing', array($this, 'adopt_listing') );
        add_action( 'wp_ajax_a1woobay_resync_from_ebay', array($this, 'resync_from_ebay') );
        add_action( 'wp_ajax_a1woobay_get_category_aspects', array($this, 'get_category_aspects') );
        add_action( 'wp_ajax_a1woobay_manual_sync', array($this, 'manual_sync') );
        add_action( 'wp_ajax_a1woobay_import_orders', array($this, 'import_orders') );
        add_action( 'wp_ajax_a1woobay_push_tracking', array($this, 'push_tracking') );
        add_action( 'wp_ajax_a1woobay_switch_profile', array($this, 'switch_profile') );
    }

    // -------------------------------------------------------------------------
    // Admin UI helpers
    // -------------------------------------------------------------------------
    public function search_categories() {
        check_ajax_referer( 'a1woobay_admin_ajax', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $query = sanitize_text_field( wp_unslash( $_POST['query'] ?? $_POST['q'] ?? '' ) );
        if ( strlen( $query ) < 2 ) {
            wp_send_json_error( array(
                'message' => 'Search term too short.',
            ) );
        }
        $api = A1WooBay_API::get_instance();
        $result = $api->search_categories( $query );
        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array(
                'message' => $result->get_error_message(),
            ) );
        }
        $suggestions = array();
        foreach ( $result['categorySuggestions'] ?? array() as $s ) {
            $path = array();
            foreach ( array_reverse( $s['categoryTreeNodeAncestors'] ?? array() ) as $anc ) {
                $path[] = $anc['categoryName'];
            }
            $path[] = $s['category']['categoryName'];
            $suggestions[] = array(
                'id'   => $s['category']['categoryId'],
                'name' => $s['category']['categoryName'],
                'path' => implode( ' > ', $path ),
            );
            if ( count( $suggestions ) >= 15 ) {
                break;
            }
        }
        wp_send_json_success( array(
            'categories' => $suggestions,
        ) );
    }

    public function get_policies() {
        check_ajax_referer( 'a1woobay_admin_ajax', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $api = A1WooBay_API::get_instance();
        $errors = array();
        $fulfill = $api->get_fulfillment_policies();
        $ret = $api->get_return_policies();
        $pay = $api->get_payment_policies();
        $map = function ( $res, $key ) use(&$errors) {
            if ( is_wp_error( $res ) ) {
                $errors[] = $res->get_error_message();
                return array();
            }
            $out = array();
            foreach ( $res[$key] ?? array() as $p ) {
                $out[] = array(
                    'id'   => $p['fulfillmentPolicyId'] ?? $p['returnPolicyId'] ?? $p['paymentPolicyId'] ?? '',
                    'name' => $p['name'] ?? '',
                );
            }
            return $out;
        };
        wp_send_json_success( array(
            'fulfillment' => $map( $fulfill, 'fulfillmentPolicies' ),
            'return'      => $map( $ret, 'returnPolicies' ),
            'payment'     => $map( $pay, 'paymentPolicies' ),
            'errors'      => $errors,
        ) );
    }

    // -------------------------------------------------------------------------
    // Listing actions
    // -------------------------------------------------------------------------
    public function verify_product() {
        check_ajax_referer( 'a1woobay_product_action', 'nonce' );
        if ( !current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        $product = wc_get_product( $product_id );
        if ( !$product ) {
            wp_send_json_error( array(
                'message' => 'Product not found.',
            ) );
        }
        $profile_id = A1WooBay_Product_Meta::get_profile_id( $product_id );
        $template_id = A1WooBay_Product_Meta::get_template_id( $product_id );
        if ( !$profile_id ) {
            wp_send_json_error( array(
                'message' => 'No eBay profile assigned. Edit the product and select a profile.',
            ) );
        }
        $profile = A1WooBay_Profiles::get_profile( $profile_id );
        if ( !$profile ) {
            wp_send_json_error( array(
                'message' => 'Assigned profile not found.',
            ) );
        }
        $m = A1WooBay_Profiles::get_meta( $profile_id );
        // Resolve category: POST value (from metabox UI) > saved product meta > profile default
        $post_cat_id = sanitize_text_field( wp_unslash( $_POST['cat_id'] ?? '' ) );
        $post_cat_name = sanitize_text_field( wp_unslash( $_POST['cat_name'] ?? '' ) );
        if ( $post_cat_id ) {
            update_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_CAT_ID, $post_cat_id );
            update_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_CAT_NAME, $post_cat_name );
        }
        $saved_cat_id = A1WooBay_Product_Meta::get_product_category_id( $product_id );
        $effective_cat_id = ( (( $post_cat_id ?: $saved_cat_id )) ?: $m['category_id'] ?? '' );
        if ( empty( $effective_cat_id ) ) {
            wp_send_json_error( array(
                'message' => 'No eBay category set. Add one to this product or set a default in the profile.',
            ) );
        }
        // Resolve condition: POST > saved product meta > profile
        $post_condition = sanitize_text_field( wp_unslash( $_POST['product_condition'] ?? '' ) );
        if ( $post_condition ) {
            update_post_meta( $product_id, '_a1wb_ebay_condition', $post_condition );
        }
        $saved_condition = get_post_meta( $product_id, '_a1wb_ebay_condition', true );
        $effective_condition = ( (( $post_condition ?: $saved_condition )) ?: $m['condition'] );
        if ( empty( $effective_condition ) ) {
            wp_send_json_error( array(
                'message' => 'No item condition set. Select a condition in the eBay Listing panel or set one in the profile.',
            ) );
        }
        if ( empty( $m['policy_ship'] ) ) {
            wp_send_json_error( array(
                'message' => 'Profile is missing a fulfillment (shipping) policy. Edit the profile and load your policies.',
            ) );
        }
        if ( empty( $m['policy_return'] ) ) {
            wp_send_json_error( array(
                'message' => 'Profile is missing a return policy.',
            ) );
        }
        $api = A1WooBay_API::get_instance();
        $loc = $api->ensure_merchant_location( $m['location'] ?? '', $m['postal_code'] ?? '', $m['country'] ?? 'US' );
        if ( is_wp_error( $loc ) ) {
            wp_send_json_error( array(
                'message' => $loc->get_error_message(),
            ) );
        }
        $sku = ( $product->get_sku() ?: 'a1wb-' . $product_id );
        $image_urls = array();
        // Build aspects from profile item specifics
        $aspects = array();
        foreach ( $m['item_specifics'] ?? array() as $spec ) {
            if ( empty( $spec['name'] ) ) {
                continue;
            }
            if ( 'attribute' === ($spec['source'] ?? 'custom') ) {
                $val = $product->get_attribute( $spec['value'] ?? '' );
                if ( $val ) {
                    $aspects[$spec['name']] = array($val);
                }
            } else {
                if ( !empty( $spec['value'] ) ) {
                    $aspects[$spec['name']] = array($spec['value']);
                }
            }
        }
        // Per-product identifiers: Brand and MPN override/supplement profile aspects
        $prod_brand = A1WooBay_Product_Meta::get_brand( $product_id );
        $prod_mpn = A1WooBay_Product_Meta::get_mpn( $product_id );
        $prod_upc = A1WooBay_Product_Meta::get_upc( $product_id );
        if ( $prod_brand ) {
            $aspects['Brand'] = array($prod_brand);
        } elseif ( !isset( $aspects['Brand'] ) ) {
            $aspects['Brand'] = array('Unbranded');
        }
        if ( $prod_mpn ) {
            $aspects['MPN'] = array($prod_mpn);
        }
        // Per-product item specifics: merge on top of profile (product wins on conflict)
        $prod_specifics = A1WooBay_Product_Meta::get_item_specifics( $product_id );
        foreach ( $prod_specifics as $pspec ) {
            if ( empty( $pspec['name'] ) ) {
                continue;
            }
            if ( 'attribute' === ($pspec['source'] ?? 'custom') ) {
                $val = $product->get_attribute( $pspec['value'] ?? '' );
                if ( $val ) {
                    $aspects[$pspec['name']] = array($val);
                }
            } elseif ( !empty( $pspec['value'] ) ) {
                $aspects[$pspec['name']] = array($pspec['value']);
            }
        }
        // Resolve listing title: per-product custom title > product name (both truncated to 80)
        $custom_title = A1WooBay_Product_Meta::get_custom_title( $product_id );
        $ebay_title = ( $custom_title ? self::truncate_ebay_title( $custom_title ) : self::truncate_ebay_title( $product->get_name() ) );
        // Resolve condition description: per-product overrides profile
        $prod_cond_desc = A1WooBay_Product_Meta::get_condition_desc( $product_id );
        $effective_cond_desc = ( $prod_cond_desc ?: $m['condition_desc'] ?? '' );
        $inventory_item = array(
            'availability'         => array(
                'shipToLocationAvailability' => array(
                    'quantity' => max( 1, ( (int) $product->get_stock_quantity() ?: 1 ) ),
                ),
            ),
            'condition'            => $effective_condition,
            'conditionDescription' => $effective_cond_desc,
            'product'              => array(
                'title'     => $ebay_title,
                'imageUrls' => $image_urls,
                'aspects'   => $aspects,
            ),
        );
        // Add UPC if set (eBay uses GTINs for catalog matching)
        if ( $prod_upc ) {
            $inventory_item['product']['upc'] = array($prod_upc);
        }
        $weight = (float) $product->get_weight();
        if ( $weight > 0 ) {
            $wc_weight_unit = get_option( 'woocommerce_weight_unit', 'lbs' );
            $ebay_weight_unit_map = array(
                'lbs' => 'POUND',
                'oz'  => 'OUNCE',
                'kg'  => 'KILOGRAM',
                'g'   => 'GRAM',
            );
            $ebay_weight_unit = $ebay_weight_unit_map[$wc_weight_unit] ?? 'POUND';
            $inventory_item['packageWeightAndSize'] = array(
                'weight' => array(
                    'value' => $weight,
                    'unit'  => $ebay_weight_unit,
                ),
            );
        }
        $item_result = $api->create_or_update_inventory_item( $sku, $inventory_item );
        if ( is_wp_error( $item_result ) ) {
            A1WooBay_Product_Meta::set_listing_error( $product_id, $item_result->get_error_message() );
            wp_send_json_error( array(
                'message' => 'Inventory item error: ' . $item_result->get_error_message(),
            ) );
        }
        // Description Templates are a Pro-only feature (WordPress.org
        // Guideline 5) - physically absent from the free/wp.org build.
        $description = '';
        if ( !$description ) {
            $description = '<p>' . wp_kses_post( ( $product->get_description() ?: $product->get_short_description() ) ) . '</p>';
        }
        $price = $this->calculate_price( $product, $m );
        if ( $price <= 0 ) {
            wp_send_json_error( array(
                'message' => 'Product price is 0. Set a price before listing on eBay.',
            ) );
        }
        $offer_data = array(
            'sku'                 => $sku,
            'marketplaceId'       => A1WooBay_API::MARKETPLACE,
            'format'              => 'FIXED_PRICE',
            'availableQuantity'   => max( 1, ( (int) $product->get_stock_quantity() ?: 1 ) ),
            'categoryId'          => $effective_cat_id,
            'listingDescription'  => $description,
            'listingDuration'     => ( get_post_meta( $product->get_id(), '_a1wb_prod_duration', true ) ?: (( $m['duration'] ?: 'GTC' )) ),
            'listingPolicies'     => array(
                'fulfillmentPolicyId' => $m['policy_ship'],
                'returnPolicyId'      => $m['policy_return'],
            ),
            'pricingSummary'      => array(
                'price' => array(
                    'currency' => ( $m['currency'] ?: 'USD' ),
                    'value'    => number_format(
                        $price,
                        2,
                        '.',
                        ''
                    ),
                ),
            ),
            'merchantLocationKey' => A1WooBay_API::LOCATION_KEY,
        );
        if ( !empty( $m['policy_pay'] ) ) {
            $offer_data['listingPolicies']['paymentPolicyId'] = $m['policy_pay'];
        }
        if ( !empty( $m['category2_id'] ) ) {
            $offer_data['secondaryCategoryId'] = $m['category2_id'];
        }
        $offer_result = $api->create_or_update_offer( $sku, $offer_data );
        if ( is_wp_error( $offer_result ) ) {
            A1WooBay_Product_Meta::set_listing_error( $product_id, $offer_result->get_error_message() );
            wp_send_json_error( array(
                'message' => 'Offer error: ' . $offer_result->get_error_message(),
            ) );
        }
        $offer_id = $offer_result['offerId'];
        A1WooBay_Product_Meta::set_offer_id( $product_id, $offer_id );
        A1WooBay_Product_Meta::clear_needs_revision( $product_id );
        // If this product already has a live eBay listing (adopted or previously published),
        // go back to 'active' so Revise shows instead of Publish.
        $existing_item_id = A1WooBay_Product_Meta::get_ebay_item_id( $product_id );
        if ( $existing_item_id ) {
            A1WooBay_Product_Meta::set_listing_active( $product_id );
            wp_send_json_success( array(
                'message'  => 'Verified! Use Revise to push changes to eBay.',
                'offer_id' => $offer_id,
            ) );
        } else {
            A1WooBay_Product_Meta::set_listing_verified( $product_id );
            wp_send_json_success( array(
                'message'  => 'Verified! Ready to publish.',
                'offer_id' => $offer_id,
            ) );
        }
    }

    /**
     * Revise an active listing: updates inventory item + offer then re-publishes.
     * Used by bulk revise. Reads entirely from saved product meta — no POST overrides.
     */
    /**
     * Thin AJAX wrapper around do_revise().
     */
    public function revise_product() {
        check_ajax_referer( 'a1woobay_product_action', 'nonce' );
        if ( !current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        if ( !wc_get_product( $product_id ) ) {
            wp_send_json_error( array(
                'message' => 'Product not found.',
            ) );
        }
        $result = self::do_revise( $product_id );
        if ( $result['success'] ) {
            wp_send_json_success( array(
                'message'    => $result['message'],
                'listing_id' => $result['listing_id'] ?? '',
            ) );
        } else {
            wp_send_json_error( array(
                'message' => $result['message'],
            ) );
        }
    }

    /**
     * Revise an active eBay listing entirely from saved product/profile meta.
     * Safe to call from any PHP context (not just AJAX) — returns an array with
     * 'success' (bool), 'message' (string), and optionally 'listing_id' (string).
     *
     * @param int $product_id WC product ID.
     * @return array{success: bool, message: string, listing_id?: string}
     */
    public static function do_revise( int $product_id ) : array {
        $product = wc_get_product( $product_id );
        if ( !$product ) {
            return array(
                'success' => false,
                'message' => 'Product not found.',
            );
        }
        $offer_id = A1WooBay_Product_Meta::get_offer_id( $product_id );
        if ( !$offer_id ) {
            return array(
                'success' => false,
                'message' => 'No offer found. Verify this listing first.',
            );
        }
        $profile_id = A1WooBay_Product_Meta::get_profile_id( $product_id );
        $template_id = A1WooBay_Product_Meta::get_template_id( $product_id );
        if ( !$profile_id ) {
            return array(
                'success' => false,
                'message' => 'No eBay profile assigned.',
            );
        }
        $m = A1WooBay_Profiles::get_meta( $profile_id );
        $effective_cat_id = ( A1WooBay_Product_Meta::get_product_category_id( $product_id ) ?: $m['category_id'] ?? '' );
        $effective_condition = ( get_post_meta( $product_id, '_a1wb_ebay_condition', true ) ?: $m['condition'] ?? '' );
        if ( empty( $effective_cat_id ) ) {
            return array(
                'success' => false,
                'message' => 'No eBay category set.',
            );
        }
        if ( empty( $effective_condition ) ) {
            return array(
                'success' => false,
                'message' => 'No item condition set.',
            );
        }
        $api = A1WooBay_API::get_instance();
        $sku = ( $product->get_sku() ?: 'a1wb-' . $product_id );
        // Images (Pro only - see A1WooBay_License::allow_image_sync()).
        // Stripped entirely from the free/wp.org build (WordPress.org
        // Guideline 5) - this "if" block is auto-removed by Freemius's
        // code-stripping build step. Must be an isolated is__premium_only()
        // condition (no && / || in the same expression) - confirmed against
        // an actual Freemius-generated free zip that a compound condition
        // does NOT get stripped, only this exact documented form does.
        $image_urls = array();
        // Aspects
        $aspects = array();
        foreach ( $m['item_specifics'] ?? array() as $spec ) {
            if ( empty( $spec['name'] ) ) {
                continue;
            }
            if ( 'attribute' === ($spec['source'] ?? 'custom') ) {
                $val = $product->get_attribute( $spec['value'] ?? '' );
                if ( $val ) {
                    $aspects[$spec['name']] = array($val);
                }
            } elseif ( !empty( $spec['value'] ) ) {
                $aspects[$spec['name']] = array($spec['value']);
            }
        }
        $prod_brand = A1WooBay_Product_Meta::get_brand( $product_id );
        $prod_mpn = A1WooBay_Product_Meta::get_mpn( $product_id );
        $prod_upc = A1WooBay_Product_Meta::get_upc( $product_id );
        if ( $prod_brand ) {
            $aspects['Brand'] = array($prod_brand);
        } elseif ( !isset( $aspects['Brand'] ) ) {
            $aspects['Brand'] = array('Unbranded');
        }
        if ( $prod_mpn ) {
            $aspects['MPN'] = array($prod_mpn);
        }
        foreach ( A1WooBay_Product_Meta::get_item_specifics( $product_id ) as $pspec ) {
            if ( empty( $pspec['name'] ) ) {
                continue;
            }
            if ( 'attribute' === ($pspec['source'] ?? 'custom') ) {
                $val = $product->get_attribute( $pspec['value'] ?? '' );
                if ( $val ) {
                    $aspects[$pspec['name']] = array($val);
                }
            } elseif ( !empty( $pspec['value'] ) ) {
                $aspects[$pspec['name']] = array($pspec['value']);
            }
        }
        $custom_title = A1WooBay_Product_Meta::get_custom_title( $product_id );
        $ebay_title = ( $custom_title ? self::truncate_ebay_title( $custom_title ) : self::truncate_ebay_title( $product->get_name() ) );
        $effective_cond_desc = ( A1WooBay_Product_Meta::get_condition_desc( $product_id ) ?: $m['condition_desc'] ?? '' );
        $inventory_item = array(
            'availability'         => array(
                'shipToLocationAvailability' => array(
                    'quantity' => max( 1, ( (int) $product->get_stock_quantity() ?: 1 ) ),
                ),
            ),
            'condition'            => $effective_condition,
            'conditionDescription' => $effective_cond_desc,
            'product'              => array(
                'title'     => $ebay_title,
                'imageUrls' => $image_urls,
                'aspects'   => $aspects,
            ),
        );
        if ( $prod_upc ) {
            $inventory_item['product']['upc'] = array($prod_upc);
        }
        $weight = (float) $product->get_weight();
        if ( $weight > 0 ) {
            $wc_weight_unit = get_option( 'woocommerce_weight_unit', 'lbs' );
            $ebay_weight_unit_map = array(
                'lbs' => 'POUND',
                'oz'  => 'OUNCE',
                'kg'  => 'KILOGRAM',
                'g'   => 'GRAM',
            );
            $inventory_item['packageWeightAndSize'] = array(
                'weight' => array(
                    'value' => $weight,
                    'unit'  => $ebay_weight_unit_map[$wc_weight_unit] ?? 'POUND',
                ),
            );
        }
        $item_result = $api->create_or_update_inventory_item( $sku, $inventory_item );
        if ( is_wp_error( $item_result ) ) {
            A1WooBay_Product_Meta::set_listing_error( $product_id, $item_result->get_error_message() );
            return array(
                'success' => false,
                'message' => 'Inventory update failed: ' . $item_result->get_error_message(),
            );
        }
        // Description Templates are a Pro-only feature (WordPress.org
        // Guideline 5) - physically absent from the free/wp.org build.
        $description = '';
        if ( !$description ) {
            $description = '<p>' . wp_kses_post( ( $product->get_description() ?: $product->get_short_description() ) ) . '</p>';
        }
        $price = self::calculate_price( $product, $m );
        $offer_data = array(
            'sku'                 => $sku,
            'marketplaceId'       => A1WooBay_API::MARKETPLACE,
            'format'              => 'FIXED_PRICE',
            'availableQuantity'   => max( 1, ( (int) $product->get_stock_quantity() ?: 1 ) ),
            'categoryId'          => $effective_cat_id,
            'listingDescription'  => $description,
            'listingDuration'     => ( get_post_meta( $product->get_id(), '_a1wb_prod_duration', true ) ?: (( $m['duration'] ?: 'GTC' )) ),
            'listingPolicies'     => array(
                'fulfillmentPolicyId' => $m['policy_ship'] ?? '',
                'returnPolicyId'      => $m['policy_return'] ?? '',
            ),
            'pricingSummary'      => array(
                'price' => array(
                    'currency' => ( $m['currency'] ?: 'USD' ),
                    'value'    => number_format(
                        $price,
                        2,
                        '.',
                        ''
                    ),
                ),
            ),
            'merchantLocationKey' => A1WooBay_API::LOCATION_KEY,
        );
        if ( !empty( $m['policy_pay'] ) ) {
            $offer_data['listingPolicies']['paymentPolicyId'] = $m['policy_pay'];
        }
        if ( !empty( $m['category2_id'] ) ) {
            $offer_data['secondaryCategoryId'] = $m['category2_id'];
        }
        $offer_result = $api->create_or_update_offer( $sku, $offer_data );
        if ( is_wp_error( $offer_result ) ) {
            return array(
                'success' => false,
                'message' => 'Offer update failed: ' . $offer_result->get_error_message(),
            );
        }
        $pub_result = $api->publish_offer( $offer_id );
        if ( is_wp_error( $pub_result ) ) {
            A1WooBay_Product_Meta::set_listing_error( $product_id, $pub_result->get_error_message() );
            return array(
                'success' => false,
                'message' => 'Revise failed: ' . $pub_result->get_error_message(),
            );
        }
        $listing_id = $pub_result['listingId'] ?? '';
        A1WooBay_Product_Meta::set_listing_active( $product_id, $listing_id );
        return array(
            'success'    => true,
            'message'    => 'Listing revised successfully.',
            'listing_id' => $listing_id,
        );
    }

    /**
     * Switch the eBay profile assigned to a product (AJAX).
     */
    public function switch_profile() {
        check_ajax_referer( 'a1woobay_product_action', 'nonce' );
        if ( !current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        $profile_id = absint( wp_unslash( $_POST['profile_id'] ?? 0 ) );
        if ( !wc_get_product( $product_id ) ) {
            wp_send_json_error( array(
                'message' => 'Product not found.',
            ) );
        }
        if ( $profile_id ) {
            $profile = get_post( $profile_id );
            if ( !$profile || 'a1woobay_profile' !== $profile->post_type ) {
                wp_send_json_error( array(
                    'message' => 'Profile not found.',
                ) );
            }
            update_post_meta( $product_id, A1WooBay_Product_Meta::META_PROFILE_ID, $profile_id );
            $profile_name = $profile->post_title;
        } else {
            delete_post_meta( $product_id, A1WooBay_Product_Meta::META_PROFILE_ID );
            $profile_name = '';
        }
        wp_send_json_success( array(
            'message'      => ( $profile_id ? 'Profile switched to: ' . $profile_name : 'Profile removed.' ),
            'profile_name' => $profile_name,
        ) );
    }

    public function push_product() {
        check_ajax_referer( 'a1woobay_product_action', 'nonce' );
        if ( !current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        $product = wc_get_product( $product_id );
        if ( !$product ) {
            wp_send_json_error( array(
                'message' => 'Product not found.',
            ) );
        }
        $offer_id = A1WooBay_Product_Meta::get_offer_id( $product_id );
        if ( !$offer_id ) {
            wp_send_json_error( array(
                'message' => 'No offer found. Please verify the listing first.',
            ) );
        }
        $api = A1WooBay_API::get_instance();
        $result = $api->publish_offer( $offer_id );
        if ( is_wp_error( $result ) ) {
            A1WooBay_Product_Meta::set_listing_error( $product_id, $result->get_error_message() );
            wp_send_json_error( array(
                'message' => 'Publish failed: ' . $result->get_error_message(),
            ) );
        }
        $listing_id = $result['listingId'] ?? '';
        A1WooBay_Product_Meta::set_listing_active( $product_id, $listing_id );
        wp_send_json_success( array(
            'message'    => 'Published! Listing is now live.',
            'listing_id' => $listing_id,
        ) );
    }

    /**
     * End a live eBay listing, callable from any PHP context.
     * Safe to call outside AJAX (e.g. from the stock-change hook).
     *
     * @param int $product_id
     * @return array{success: bool, message: string}
     */
    public static function do_end_listing( int $product_id ) : array {
        $offer_id = A1WooBay_Product_Meta::get_offer_id( $product_id );
        if ( $offer_id ) {
            $api = A1WooBay_API::get_instance();
            $result = $api->withdraw_offer( $offer_id );
            if ( is_wp_error( $result ) ) {
                return array(
                    'success' => false,
                    'message' => 'End listing failed: ' . $result->get_error_message(),
                );
            }
        }
        A1WooBay_Product_Meta::set_listing_ended( $product_id );
        return array(
            'success' => true,
            'message' => 'Listing ended.',
        );
    }

    /**
     * AJAX wrapper around do_end_listing().
     */
    public function end_listing() {
        check_ajax_referer( 'a1woobay_product_action', 'nonce' );
        if ( !current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        $result = self::do_end_listing( $product_id );
        if ( $result['success'] ) {
            wp_send_json_success( array(
                'message' => $result['message'],
            ) );
        } else {
            wp_send_json_error( array(
                'message' => $result['message'],
            ) );
        }
    }

    public function mark_sold() {
        check_ajax_referer( 'a1woobay_product_action', 'nonce' );
        if ( !current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        $product = wc_get_product( $product_id );
        if ( !$product ) {
            wp_send_json_error( array(
                'message' => 'Product not found.',
            ) );
        }
        // End the listing on eBay if we have an offer ID
        $offer_id = A1WooBay_Product_Meta::get_offer_id( $product_id );
        if ( $offer_id ) {
            $api = A1WooBay_API::get_instance();
            $result = $api->withdraw_offer( $offer_id );
            // Don't block on eBay error - still mark sold locally
        }
        // Set WooCommerce stock to 0 / out of stock
        $product->set_stock_quantity( 0 );
        $product->set_stock_status( 'outofstock' );
        $product->save();
        wc_update_product_stock_status( $product_id, 'outofstock' );
        // Update plugin status
        A1WooBay_Product_Meta::set_listing_sold( $product_id );
        wp_send_json_success( array(
            'message' => 'Marked as sold. WooCommerce stock set to 0.',
        ) );
    }

    // -------------------------------------------------------------------------
    // Helpers
    // -------------------------------------------------------------------------
    private static function calculate_price( $product, $profile_meta ) {
        // Product-level override takes priority over profile setting.
        $prod_type = get_post_meta( $product->get_id(), '_a1wb_price_type', true );
        if ( $prod_type ) {
            $type = $prod_type;
            $val = (float) get_post_meta( $product->get_id(), '_a1wb_price_value', true );
        } else {
            $type = $profile_meta['price_type'] ?? 'none';
            $val = (float) ($profile_meta['price_value'] ?? 0);
        }
        switch ( $type ) {
            case 'sale_price':
                $price = (float) (( $product->get_sale_price() ?: $product->get_price() ));
                break;
            case 'regular_price':
                $price = (float) $product->get_regular_price();
                break;
            case 'percent':
                $price = (float) $product->get_price() * (1 + $val / 100);
                break;
            case 'fixed':
                $price = $val;
                break;
            default:
                $price = (float) $product->get_price();
        }
        return round( $price, 2 );
    }

    private static function truncate_ebay_title( $title ) {
        if ( mb_strlen( $title ) <= 80 ) {
            return $title;
        }
        $trimmed = mb_substr( $title, 0, 80 );
        $last_space = mb_strrpos( $trimmed, ' ' );
        if ( $last_space > 50 ) {
            $trimmed = mb_substr( $trimmed, 0, $last_space );
        }
        return rtrim( $trimmed );
    }

    public function fetch_ebay_inventory() {
        check_ajax_referer( 'a1woobay_admin_ajax', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $api = A1WooBay_API::get_instance();
        $result = $api->get_inventory_items( 200, 0 );
        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array(
                'message' => $result->get_error_message(),
            ) );
        }
        $inventory_items = $result['inventoryItems'] ?? array();
        if ( empty( $inventory_items ) ) {
            wp_send_json_success( array(
                'items' => array(),
            ) );
        }
        // Build a SKU -> WC product map for fast lookup
        $wc_by_sku = array();
        $wc_query = new WP_Query(array(
            'post_type'      => 'product',
            'post_status'    => 'publish',
            'posts_per_page' => 500,
        ));
        foreach ( $wc_query->posts as $p ) {
            $product = wc_get_product( $p->ID );
            if ( !$product ) {
                continue;
            }
            $sku = $product->get_sku();
            if ( $sku ) {
                $wc_by_sku[$sku] = array(
                    'id'       => $p->ID,
                    'name'     => $p->post_title,
                    'edit_url' => get_edit_post_link( $p->ID, 'raw' ),
                );
            }
        }
        $items = array();
        foreach ( $inventory_items as $inv ) {
            $sku = $inv['sku'] ?? '';
            $title = $inv['product']['title'] ?? $sku;
            // Get offer info for this SKU
            $offer_id = '';
            $listing_id = '';
            $ebay_status = '';
            $offer_res = $api->get_offers_by_sku( $sku );
            if ( !is_wp_error( $offer_res ) && !empty( $offer_res['offers'] ) ) {
                $offer = $offer_res['offers'][0];
                $offer_id = $offer['offerId'] ?? '';
                $listing_id = $offer['listing']['listingId'] ?? '';
                $ebay_status = $offer['status'] ?? '';
            }
            // Match to WC product
            $wc_product_id = 0;
            $wc_product_name = '';
            $wc_edit_url = '';
            if ( isset( $wc_by_sku[$sku] ) ) {
                $wc_product_id = $wc_by_sku[$sku]['id'];
                $wc_product_name = $wc_by_sku[$sku]['name'];
                $wc_edit_url = $wc_by_sku[$sku]['edit_url'];
            }
            // Check if already tracked in A1-WooBay
            $already_tracked = false;
            if ( $wc_product_id ) {
                $tracked_id = A1WooBay_Product_Meta::get_ebay_item_id( $wc_product_id );
                if ( $tracked_id ) {
                    $already_tracked = true;
                }
            }
            $items[] = array(
                'sku'             => $sku,
                'title'           => $title,
                'wc_product_id'   => $wc_product_id,
                'wc_product_name' => $wc_product_name,
                'wc_edit_url'     => $wc_edit_url,
                'offer_id'        => $offer_id,
                'listing_id'      => $listing_id,
                'ebay_status'     => $ebay_status,
                'already_tracked' => $already_tracked,
            );
        }
        wp_send_json_success( array(
            'items' => $items,
        ) );
    }

    public function adopt_listing() {
        check_ajax_referer( 'a1woobay_admin_ajax', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        $item_id = sanitize_text_field( wp_unslash( $_POST['item_id'] ?? '' ) );
        $offer_id = sanitize_text_field( wp_unslash( $_POST['offer_id'] ?? '' ) );
        if ( !$product_id ) {
            wp_send_json_error( array(
                'message' => 'No product specified.',
            ) );
        }
        if ( !$item_id ) {
            wp_send_json_error( array(
                'message' => 'No eBay Item ID provided.',
            ) );
        }
        $product = wc_get_product( $product_id );
        if ( !$product ) {
            wp_send_json_error( array(
                'message' => 'Product not found.',
            ) );
        }
        // Save item ID and set status to active
        A1WooBay_Product_Meta::set_listing_active( $product_id, $item_id );
        // Save offer ID if provided
        if ( $offer_id ) {
            A1WooBay_Product_Meta::set_offer_id( $product_id, $offer_id );
        }
        // Back-fill product identifiers and specifics from eBay data
        $api = A1WooBay_API::get_instance();
        $sku = $product->get_sku();
        if ( $sku ) {
            // Fetch inventory item for brand, MPN, UPC, aspects
            $inv = $api->get_inventory_item( $sku );
            if ( !is_wp_error( $inv ) ) {
                $ebay_product = $inv['product'] ?? array();
                // Brand
                $ebay_brand = $ebay_product['brand'] ?? '';
                if ( $ebay_brand && !get_post_meta( $product_id, A1WooBay_Product_Meta::META_BRAND, true ) ) {
                    update_post_meta( $product_id, A1WooBay_Product_Meta::META_BRAND, sanitize_text_field( $ebay_brand ) );
                }
                // MPN
                $ebay_mpn = $ebay_product['mpn'] ?? '';
                if ( $ebay_mpn && !get_post_meta( $product_id, A1WooBay_Product_Meta::META_MPN, true ) ) {
                    update_post_meta( $product_id, A1WooBay_Product_Meta::META_MPN, sanitize_text_field( $ebay_mpn ) );
                }
                // UPC / EAN (first available GTIN)
                $ebay_upc = '';
                if ( !empty( $ebay_product['upc'] ) ) {
                    $v = $ebay_product['upc'];
                    $ebay_upc = ( is_array( $v ) ? $v[0] : $v );
                } elseif ( !empty( $ebay_product['ean'] ) ) {
                    $v = $ebay_product['ean'];
                    $ebay_upc = ( is_array( $v ) ? $v[0] : $v );
                }
                if ( $ebay_upc && !get_post_meta( $product_id, A1WooBay_Product_Meta::META_UPC, true ) ) {
                    update_post_meta( $product_id, A1WooBay_Product_Meta::META_UPC, sanitize_text_field( $ebay_upc ) );
                }
                // Item specifics from aspects (skip dedicated identifier fields)
                $skip_aspects = array(
                    'Brand',
                    'MPN',
                    'UPC',
                    'EAN',
                    'ISBN',
                    'GTIN'
                );
                $aspects = $ebay_product['aspects'] ?? array();
                if ( $aspects && !get_post_meta( $product_id, A1WooBay_Product_Meta::META_ITEM_SPECIFICS, true ) ) {
                    $specs = array();
                    foreach ( $aspects as $asp_name => $asp_vals ) {
                        if ( in_array( $asp_name, $skip_aspects, true ) ) {
                            continue;
                        }
                        $specs[] = array(
                            'name'   => sanitize_text_field( $asp_name ),
                            'source' => 'custom',
                            'value'  => sanitize_text_field( ( is_array( $asp_vals ) ? $asp_vals[0] : $asp_vals ) ),
                        );
                    }
                    if ( $specs ) {
                        update_post_meta( $product_id, A1WooBay_Product_Meta::META_ITEM_SPECIFICS, $specs );
                    }
                }
            }
            // Category ID from offer
            $offer_res = $api->get_offers_by_sku( $sku );
            if ( !is_wp_error( $offer_res ) && !empty( $offer_res['offers'] ) ) {
                $off = $offer_res['offers'][0];
                $off_cat = sanitize_text_field( $off['categoryId'] ?? '' );
                if ( $off_cat && !get_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_CAT_ID, true ) ) {
                    update_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_CAT_ID, $off_cat );
                    update_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_CAT_NAME, 'eBay Cat ' . $off_cat );
                }
            }
        }
        wp_send_json_success( array(
            'message'  => 'Listing adopted successfully for "' . $product->get_name() . '".',
            'edit_url' => get_edit_post_link( $product_id, 'raw' ),
        ) );
    }

    public function resync_from_ebay() {
        check_ajax_referer( 'a1woobay_product_action', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $product_id = absint( wp_unslash( $_POST['product_id'] ?? 0 ) );
        if ( !$product_id ) {
            wp_send_json_error( array(
                'message' => 'No product specified.',
            ) );
        }
        $product = wc_get_product( $product_id );
        if ( !$product ) {
            wp_send_json_error( array(
                'message' => 'Product not found.',
            ) );
        }
        $sku = $product->get_sku();
        if ( !$sku ) {
            wp_send_json_error( array(
                'message' => 'Product has no SKU.',
            ) );
        }
        $api = A1WooBay_API::get_instance();
        $updated = array();
        // --- Inventory item: brand, MPN, UPC, aspects ---
        $inv = $api->get_inventory_item( $sku );
        if ( is_wp_error( $inv ) ) {
            wp_send_json_error( array(
                'message' => 'eBay inventory item fetch failed: ' . $inv->get_error_message(),
            ) );
        }
        $ebay_product = $inv['product'] ?? array();
        $brand = sanitize_text_field( $ebay_product['brand'] ?? '' );
        if ( $brand ) {
            update_post_meta( $product_id, A1WooBay_Product_Meta::META_BRAND, $brand );
            $updated[] = 'brand';
        }
        $mpn = sanitize_text_field( $ebay_product['mpn'] ?? '' );
        if ( $mpn ) {
            update_post_meta( $product_id, A1WooBay_Product_Meta::META_MPN, $mpn );
            $updated[] = 'mpn';
        }
        $ebay_upc = '';
        if ( !empty( $ebay_product['upc'] ) ) {
            $v = $ebay_product['upc'];
            $ebay_upc = ( is_array( $v ) ? $v[0] : $v );
        } elseif ( !empty( $ebay_product['ean'] ) ) {
            $v = $ebay_product['ean'];
            $ebay_upc = ( is_array( $v ) ? $v[0] : $v );
        }
        if ( $ebay_upc ) {
            update_post_meta( $product_id, A1WooBay_Product_Meta::META_UPC, sanitize_text_field( $ebay_upc ) );
            $updated[] = 'upc';
        }
        $skip_aspects = array(
            'Brand',
            'MPN',
            'UPC',
            'EAN',
            'ISBN',
            'GTIN'
        );
        $aspects = $ebay_product['aspects'] ?? array();
        if ( $aspects ) {
            $specs = array();
            foreach ( $aspects as $asp_name => $asp_vals ) {
                if ( in_array( $asp_name, $skip_aspects, true ) ) {
                    continue;
                }
                $specs[] = array(
                    'name'   => sanitize_text_field( $asp_name ),
                    'source' => 'custom',
                    'value'  => sanitize_text_field( ( is_array( $asp_vals ) ? $asp_vals[0] : $asp_vals ) ),
                );
            }
            if ( $specs ) {
                update_post_meta( $product_id, A1WooBay_Product_Meta::META_ITEM_SPECIFICS, $specs );
                $updated[] = 'specifics';
            }
        }
        // --- Offer: category, offer ID, status recovery ---
        $offer_res = $api->get_offers_by_sku( $sku );
        if ( !is_wp_error( $offer_res ) && !empty( $offer_res['offers'] ) ) {
            $off = $offer_res['offers'][0];
            $off_cat = sanitize_text_field( $off['categoryId'] ?? '' );
            if ( $off_cat ) {
                update_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_CAT_ID, $off_cat );
                update_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_CAT_NAME, 'eBay Cat ' . $off_cat );
                $updated[] = 'category';
            }
            $off_id = sanitize_text_field( $off['offerId'] ?? '' );
            if ( $off_id ) {
                A1WooBay_Product_Meta::set_offer_id( $product_id, $off_id );
            }
            // Restore error status to active if eBay offer is still published
            $off_status = strtoupper( $off['status'] ?? '' );
            $local_status = get_post_meta( $product_id, A1WooBay_Product_Meta::META_EBAY_STATUS, true );
            if ( 'PUBLISHED' === $off_status && A1WooBay_Product_Meta::STATUS_ERROR === $local_status ) {
                $item_id = A1WooBay_Product_Meta::get_ebay_item_id( $product_id );
                A1WooBay_Product_Meta::set_listing_active( $product_id, $item_id );
                $updated[] = 'status-restored';
            }
        }
        // --- Watch count via Trading API ---
        $item_id_for_watch = A1WooBay_Product_Meta::get_ebay_item_id( $product_id );
        if ( $item_id_for_watch ) {
            $watch = $api->get_item_watch_count( $item_id_for_watch );
            if ( !is_wp_error( $watch ) ) {
                update_post_meta( $product_id, A1WooBay_Product_Meta::META_WATCH_COUNT, $watch );
            }
        }
        $watch_val = get_post_meta( $product_id, A1WooBay_Product_Meta::META_WATCH_COUNT, true );
        wp_send_json_success( array(
            'message'     => 'Synced.',
            'watch_count' => ( '' !== $watch_val ? (int) $watch_val : null ),
        ) );
    }

    public function get_category_aspects() {
        check_ajax_referer( 'a1woobay_admin_ajax', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        $category_id = sanitize_text_field( wp_unslash( $_POST['category_id'] ?? '' ) );
        if ( !$category_id ) {
            wp_send_json_error( array(
                'message' => 'No category ID provided.',
            ) );
        }
        $api = A1WooBay_API::get_instance();
        $result = $api->get_item_aspects_for_category( $category_id );
        if ( is_wp_error( $result ) ) {
            wp_send_json_error( array(
                'message' => $result->get_error_message(),
            ) );
        }
        // Normalize: skip dedicated identifier fields, return name/usage/values
        $skip = array(
            'Brand',
            'MPN',
            'UPC',
            'EAN',
            'ISBN',
            'GTIN',
            'Manufacturer Part Number'
        );
        $aspects = $result['aspects'] ?? array();
        $required = array();
        $recommended = array();
        $optional = array();
        foreach ( $aspects as $asp ) {
            $name = $asp['localizedAspectName'] ?? '';
            if ( !$name || in_array( $name, $skip, true ) ) {
                continue;
            }
            $constraint = $asp['aspectConstraint'] ?? array();
            $usage = strtoupper( $constraint['aspectUsage'] ?? 'OPTIONAL' );
            $cardinality = strtoupper( $constraint['aspectCardinality'] ?? 'SINGLE' );
            // Collect allowed values (up to 100 for browser)
            $allowed = array();
            if ( !empty( $asp['aspectValues'] ) ) {
                foreach ( array_slice( $asp['aspectValues'], 0, 100 ) as $av ) {
                    $lv = $av['localizedValue'] ?? '';
                    if ( $lv ) {
                        $allowed[] = $lv;
                    }
                }
            }
            $item = array(
                'name'        => $name,
                'usage'       => $usage,
                'cardinality' => $cardinality,
                'values'      => $allowed,
            );
            if ( 'REQUIRED' === $usage ) {
                $required[] = $item;
            } elseif ( 'RECOMMENDED' === $usage ) {
                $recommended[] = $item;
            } else {
                $optional[] = $item;
            }
        }
        wp_send_json_success( array(
            'required'    => $required,
            'recommended' => $recommended,
            'optional'    => $optional,
        ) );
    }

    /**
     * AJAX: manually trigger pull sync (eBay → WC).
     */
    public function manual_sync() : void {
        check_ajax_referer( 'a1woobay_manual_sync', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( 'Unauthorized' );
        }
        $sync = A1WooBay_Sync::get_instance();
        $result = $sync->run_pull_sync();
        $msg = sprintf(
            /* translators: 1: number of products updated, 2: total products checked, 3: number of errors */
            __( 'Done: %1$d of %2$d products updated, %3$d errors.', 'a1-marketplace-sync-with-ebay-for-woocommerce' ),
            (int) $result['updated'],
            (int) $result['total'],
            (int) $result['errors']
        );
        wp_send_json_success( array(
            'message' => $msg,
            'result'  => $result,
        ) );
    }

    /**
     * AJAX: manually trigger eBay order import.
     */
    public function import_orders() : void {
        check_ajax_referer( 'a1woobay_import_orders', 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( 'Unauthorized' );
        }
        wp_send_json_error( A1WooBay_License::order_import_message() );
    }

    // -------------------------------------------------------------------------
    // Phase 3c - Push tracking to eBay
    // -------------------------------------------------------------------------
    public function push_tracking() : void {
        $order_id = absint( wp_unslash( $_POST['order_id'] ?? 0 ) );
        check_ajax_referer( 'a1wb_push_tracking_' . $order_id, 'nonce' );
        if ( !current_user_can( 'manage_woocommerce' ) ) {
            wp_send_json_error( array(
                'message' => 'Permission denied.',
            ) );
        }
        wp_send_json_error( array(
            'message' => A1WooBay_License::order_import_message(),
        ) );
    }

}
