<?php

defined('ABSPATH') || exit;

/**
 * Class ShopCentral_Product_Sync_Manager
 * Handles automatic product and inventory synchronization across multiple stores.
 */
class ShopCentral_Product_Sync_Manager
{
    private $namespace = 'shopcentral/v1';

    public function __construct()
    {
        // Hook for product updates (details like price, description, etc.)
        add_action('woocommerce_update_product', [$this, 'sync_product_details'], 20, 1);
        
        // Hook for stock changes
        add_action('woocommerce_product_set_stock', [$this, 'sync_product_stock'], 20, 1);
        add_action('woocommerce_variation_set_stock', [$this, 'sync_product_stock'], 20, 1);
        
        // Handle stock reduction during checkout
        add_action('woocommerce_reduce_order_stock', [$this, 'sync_order_stock_reduction'], 20, 1);

        // Register REST API route for incoming syncs (Bidirectional)
        add_action('rest_api_init', [$this, 'register_sync_routes']);
    }

    /**
     * Register REST API routes for bidirectional sync
     */
    public function register_sync_routes()
    {
        register_rest_route($this->namespace, '/sync/order-callback', [
            'methods' => 'POST',
            'callback' => [$this, 'handle_remote_order'],
            'permission_callback' => '__return_true',
        ]);
    }

    /**
     * Handle incoming order notifications from secondary stores.
     * Now creates a true WooCommerce order on the hub for each incoming order.
     * Stock reduction logic is preserved but runs after order creation.
     */
    public function handle_remote_order($request)
    {
        $params     = $request->get_json_params();
        $source_url = $request->get_param('store_url');
        $store_id   = intval($request->get_param('store_id'));

        if (empty($params) || !isset($params['line_items'])) {
            return new WP_REST_Response(['status' => 'ignored'], 200);
        }

        if (!$this->is_store_order_import_enabled($store_id, $source_url)) {
            $this->reduce_stock_only($params, $source_url);
            return new WP_REST_Response(['status' => 'success', 'imported' => false, 'reason' => 'import_disabled'], 200);
        }

        $child_order_id = intval($params['id'] ?? 0);

        $this->log_import('WEBHOOK_RECEIVED', [
            'store_id'   => $store_id,
            'source_url' => $source_url,
            'child_id'   => $child_order_id,
            'status'     => $params['status'] ?? 'unknown',
            'has_billing'      => !empty($params['billing']),
            'has_shipping'     => !empty($params['shipping']),
            'has_line_items'   => !empty($params['line_items']),
            'line_items_count' => isset($params['line_items']) ? count($params['line_items']) : 0,
        ]);

        if ($child_order_id && $this->order_already_imported($child_order_id, $store_id, $source_url)) {
            $this->log_import('DUPLICATE_SKIP', "child_order_id={$child_order_id}");
            return new WP_REST_Response(['status' => 'success', 'imported' => false, 'reason' => 'duplicate'], 200);
        }

        try {
            $this->log_import('START_ORDER_CREATE', "child_id={$child_order_id}");
            $order = $this->create_hub_order($params, $store_id, $source_url);

            if ($order && is_a($order, 'WC_Order')) {
                $item_count = $order->get_item_count();
                $billing = $order->get_billing_first_name();
                $this->log_import('ORDER_CREATED_OK', "hub_id={$order->get_id()}, items={$item_count}, billing={$billing}");
                $this->reduce_stock_only($params, $source_url);
                $this->update_last_sync($store_id);
                return new WP_REST_Response([
                    'status'   => 'success',
                    'imported' => true,
                    'order_id' => $order->get_id(),
                    'items'    => $item_count,
                ], 200);
            }
            $this->log_import('ORDER_CREATE_RETURNED_NULL');
        } catch (\Exception $e) {
            $this->log_import('ORDER_CREATE_EXCEPTION', $e->getMessage() . ' | ' . $e->getTraceAsString());
            error_log('ShopCentral Order Import Error: ' . $e->getMessage());
            return new WP_REST_Response(['status' => 'error', 'message' => $e->getMessage()], 500);
        }

        return new WP_REST_Response(['status' => 'error'], 500);
    }

    /**
     * Check whether the child store has order import enabled.
     */
    private function is_store_order_import_enabled($store_id, $source_url)
    {
        global $wpdb;
        $table = $wpdb->prefix . 'shopcentral_stores';

        if ($store_id > 0) {
            $enabled = $wpdb->get_var($wpdb->prepare(
                "SELECT order_import_enabled FROM $table WHERE id = %d",
                $store_id
            ));
            return (int) $enabled === 1;
        }

        if (!empty($source_url)) {
            $enabled = $wpdb->get_var($wpdb->prepare(
                "SELECT order_import_enabled FROM $table WHERE url = %s",
                $source_url
            ));
            return (int) $enabled === 1;
        }

        return false;
    }

    /**
     * Log import steps for debugging.
     */
    private function log_import($message, $data = null)
    {
        $log = WP_CONTENT_DIR . '/shopcentral-order-import-debug.log';
        $line = '[' . current_time('mysql') . '] ' . $message;
        if ($data !== null) {
            $line .= ' | ' . (is_string($data) ? $data : wp_json_encode($data));
        }
        $line .= "\n";
        @file_put_contents($log, $line, FILE_APPEND);
    }

    /**
     * Mark the most recent sync time for a store.
     */
    private function update_last_sync($store_id)
    {
        if ($store_id <= 0) return;
        global $wpdb;
        $table = $wpdb->prefix . 'shopcentral_stores';
        $wpdb->update($table, ['last_order_sync' => current_time('mysql')], ['id' => $store_id]);
    }

    /**
     * Detect duplicate — returns the existing hub order ID if already imported.
     * Checks BOTH store_id (numeric) and source_url (string) for backwards compatibility
     * with older webhooks that only stored URL.
     */
    public function order_already_imported($child_order_id, $store_id, $source_url)
    {
        $store_identifier = $store_id > 0 ? (string) $store_id : $source_url;

        if (function_exists('wc_get_orders')) {
            $orders = wc_get_orders([
                'limit'      => 1,
                'return'     => 'ids',
                'meta_query' => [
                    'relation' => 'AND',
                    [
                        'key'     => '_shopcentral_child_order_id',
                        'value'   => $child_order_id,
                        'compare' => '=',
                    ],
                    [
                        'key'     => '_shopcentral_child_store',
                        'value'   => [$store_identifier, $source_url],
                        'compare' => 'IN',
                    ],
                ],
            ]);
            if (!empty($orders)) {
                return intval($orders[0]);
            }
            return 0;
        }

        global $wpdb;
        $existing = $wpdb->get_var($wpdb->prepare(
            "SELECT pm_child.post_id
             FROM {$wpdb->postmeta} pm_child
             INNER JOIN {$wpdb->postmeta} pm_store ON pm_child.post_id = pm_store.post_id
               AND pm_store.meta_key = '_shopcentral_child_store'
             WHERE pm_child.meta_key = '_shopcentral_child_order_id'
               AND pm_child.meta_value = %d
               AND (pm_store.meta_value = %s OR pm_store.meta_value = %s)
             LIMIT 1",
            $child_order_id,
            $store_identifier,
            $source_url
        ));

        return $existing ? intval($existing) : 0;
    }

    /**
     * Create the real WC_Order on the hub site.
     */
    public function create_hub_order($params, $store_id, $source_url, $customer_sync = true)
    {
        if (!function_exists('wc_create_order')) {
            $this->log_import('NO_WC_CREATE_ORDER_FUNC');
            return null;
        }

        if (!class_exists('WC_Order_Item_Product')) {
            $this->log_import('WC_Order_Item_Product_CLASS_NOT_FOUND');
            return null;
        }

        $status_map = [
            'pending'    => 'wc-pending',
            'processing' => 'wc-processing',
            'on-hold'    => 'wc-on-hold',
            'completed'  => 'wc-completed',
            'cancelled'  => 'wc-cancelled',
            'refunded'   => 'wc-refunded',
            'failed'     => 'wc-failed',
        ];
        $child_status = sanitize_text_field($params['status'] ?? 'processing');
        $hub_status   = $status_map[$child_status] ?? 'wc-on-hold';

        $store_identifier = $store_id > 0 ? (string) $store_id : $source_url;

        $order = wc_create_order([
            'status'        => $hub_status,
            'customer_note' => sanitize_textarea_field($params['customer_note'] ?? ''),
        ]);

        if (!$order || is_wp_error($order)) {
            $this->log_import('WC_CREATE_ORDER_FAILED', is_wp_error($order) ? $order->get_error_message() : 'null');
            return null;
        }

        $order_id = $order->get_id();
        $this->log_import('ORDER_OBJECT_CREATED', "hub_id={$order_id}");

        $order->update_meta_data('_shopcentral_child_order_id', intval($params['id'] ?? 0));
        $order->update_meta_data('_shopcentral_child_store', $store_identifier);
        $order->update_meta_data('_shopcentral_child_site_url', esc_url_raw($source_url));
        $order->update_meta_data('_shopcentral_imported_at', current_time('mysql'));
        $order->update_meta_data('_shopcentral_source', 'webhook');

        if ( ! empty( $params['customer_id'] ) && intval( $params['customer_id'] ) > 0 ) {
            $order->update_meta_data('_shopcentral_child_customer_id', intval( $params['customer_id'] ) );
        }

        if (!empty($params['currency'])) {
            $order->set_currency(sanitize_text_field($params['currency']));
        }

        $billing = $params['billing'] ?? [];
        if (!empty($billing) && is_array($billing)) {
            $billing = wp_unslash($billing);
            $map = [
                'first_name' => 'set_billing_first_name',
                'last_name'  => 'set_billing_last_name',
                'company'    => 'set_billing_company',
                'address_1'  => 'set_billing_address_1',
                'address_2'  => 'set_billing_address_2',
                'city'       => 'set_billing_city',
                'state'      => 'set_billing_state',
                'postcode'   => 'set_billing_postcode',
                'country'    => 'set_billing_country',
                'email'      => 'set_billing_email',
                'phone'      => 'set_billing_phone',
            ];
            $billing_applied = 0;
            foreach ($map as $key => $method) {
                if (isset($billing[$key]) && method_exists($order, $method)) {
                    try {
                        $order->$method(sanitize_text_field($billing[$key]));
                        $billing_applied++;
                    } catch (\Throwable $e) {
                        $this->log_import('BILLING_FIELD_ERROR', $method . ': ' . $e->getMessage());
                    }
                }
            }
            $this->log_import('BILLING_APPLIED', "fields={$billing_applied}");
        } else {
            $this->log_import('BILLING_EMPTY');
        }

        $shipping = $params['shipping'] ?? [];
        if (!empty($shipping) && is_array($shipping)) {
            $shipping = wp_unslash($shipping);
            $map = [
                'first_name' => 'set_shipping_first_name',
                'last_name'  => 'set_shipping_last_name',
                'company'    => 'set_shipping_company',
                'address_1'  => 'set_shipping_address_1',
                'address_2'  => 'set_shipping_address_2',
                'city'       => 'set_shipping_city',
                'state'      => 'set_shipping_state',
                'postcode'   => 'set_shipping_postcode',
                'country'    => 'set_shipping_country',
            ];
            $shipping_applied = 0;
            foreach ($map as $key => $method) {
                if (isset($shipping[$key]) && method_exists($order, $method)) {
                    try {
                        $order->$method(sanitize_text_field($shipping[$key]));
                        $shipping_applied++;
                    } catch (\Throwable $e) {
                        $this->log_import('SHIPPING_FIELD_ERROR', $method . ': ' . $e->getMessage());
                    }
                }
            }
            $this->log_import('SHIPPING_APPLIED', "fields={$shipping_applied}");
        } else {
            $this->log_import('SHIPPING_EMPTY');
        }

        if (!empty($params['payment_method'])) {
            try { $order->set_payment_method(sanitize_text_field($params['payment_method'])); } catch (\Throwable $e) {}
        }
        if (!empty($params['payment_method_title'])) {
            try { $order->set_payment_method_title(sanitize_text_field($params['payment_method_title'])); } catch (\Throwable $e) {}
        }

        if ( $customer_sync ) {
            $customer_email  = sanitize_email( $billing['email'] ?? '' );
            $customer_fname  = sanitize_text_field( $billing['first_name'] ?? '' );
            $customer_lname  = sanitize_text_field( $billing['last_name'] ?? '' );
            if ( ! empty( $customer_email ) ) {
                $customer_id = $this->get_or_create_customer( $customer_email, $customer_fname, $customer_lname, $source_url );
                if ( $customer_id ) {
                    $order->set_customer_id( $customer_id );
                    $order->update_meta_data('_shopcentral_customer_id', $customer_id );
                    $this->log_import('CUSTOMER_LINKED', "user_id={$customer_id}, hub_order={$order_id}");
                } else {
                    $this->log_import('CUSTOMER_LINK_FAILED', "email={$customer_email}, hub_order={$order_id}");
                }
            } else {
                $this->log_import('CUSTOMER_NO_EMAIL', "guest checkout, hub_order={$order_id}");
            }
        }

        $items_added = 0;
        if (!empty($params['line_items']) && is_array($params['line_items'])) {
            foreach ($params['line_items'] as $item) {
                try {
                    $this->add_imported_line_item($order, $item);
                    $items_added++;
                } catch (\Exception $e) {
                    $this->log_import('LINE_ITEM_ERROR', $e->getMessage());
                }
            }
        }
        $this->log_import('LINE_ITEMS_ADDED', "count={$items_added}");

        if (!empty($params['shipping_lines']) && is_array($params['shipping_lines'])) {
            foreach ($params['shipping_lines'] as $shipping) {
                try {
                    $item = new WC_Order_Item_Shipping();
                    $item->set_method_id(sanitize_text_field($shipping['method_id'] ?? 'manual'));
                    $item->set_method_title(sanitize_text_field($shipping['method_title'] ?? __('Shipping', 'shopcentral')));
                    $item->set_total(floatval($shipping['total'] ?? 0));
                    if (isset($shipping['taxes']) && is_array($shipping['taxes'])) {
                        $item->set_taxes($shipping['taxes']);
                    }
                    $order->add_item($item);
                    $this->log_import('SHIPPING_LINE_ADDED', sanitize_text_field($shipping['method_title'] ?? 'manual'));
                } catch (\Exception $e) {
                    $this->log_import('SHIPPING_LINE_ERROR', $e->getMessage());
                }
            }
        }

        if (!empty($params['fee_lines']) && is_array($params['fee_lines'])) {
            foreach ($params['fee_lines'] as $fee) {
                try {
                    $item = new WC_Order_Item_Fee();
                    $item->set_name(sanitize_text_field($fee['name'] ?? __('Fee', 'shopcentral')));
                    $item->set_amount(floatval($fee['total'] ?? 0));
                    $item->set_total(floatval($fee['total'] ?? 0));
                    if (isset($fee['tax_class'])) {
                        $item->set_tax_class(sanitize_text_field($fee['tax_class']));
                    }
                    if (isset($fee['tax_status'])) {
                        $item->set_tax_status(sanitize_text_field($fee['tax_status']));
                    }
                    $order->add_item($item);
                } catch (\Exception $e) {
                    $this->log_import('FEE_LINE_ERROR', $e->getMessage());
                }
            }
        }

        if (!empty($params['coupon_lines']) && is_array($params['coupon_lines'])) {
            foreach ($params['coupon_lines'] as $coupon) {
                try {
                    $this->add_imported_coupon($order, $coupon);
                } catch (\Exception $e) {
                    $this->log_import('COUPON_LINE_ERROR', $e->getMessage());
                }
            }
        }

        $props = ['shipping_total', 'discount_total'];
        foreach ($props as $prop) {
            if (isset($params[$prop]) && method_exists($order, 'set_' . $prop)) {
                try { $order->{'set_' . $prop}(floatval($params[$prop])); } catch (\Throwable $e) {}
            }
        }

        if (isset($params['total'])) {
            try { $order->set_total(floatval($params['total'])); } catch (\Throwable $e) {}
        }

        if (!empty($params['date_created'])) {
            try { $order->set_date_created($params['date_created']); } catch (\Throwable $e) {}
        }

        if (!empty($params['meta_data']) && is_array($params['meta_data'])) {
            foreach ($params['meta_data'] as $meta) {
                if (isset($meta['key'])) {
                    $order->update_meta_data(sanitize_key($meta['key']), maybe_unserialize($meta['value']));
                }
            }
        }

        try {
            $order->calculate_totals(false);
            $order->save();
            $this->log_import('ORDER_SAVED', "hub_id={$order_id}, items=" . $order->get_item_count() . ", billing=" . $order->get_billing_first_name() . ', total=' . $order->get_total());
        } catch (\Exception $e) {
            $this->log_import('ORDER_SAVE_ERROR', $e->getMessage());
            if ($order_id) {
                wp_delete_post($order_id, true);
            }
            throw $e;
        }

        return $order;
    }

    /**
     * Add a single line item trying to match an existing hub product by SKU first.
     */
    private function add_imported_line_item($order, $item)
    {
        $line = new WC_Order_Item_Product();

        $product_id = 0;
        if (!empty($item['sku'])) {
            $product_id = wc_get_product_id_by_sku(sanitize_text_field($item['sku']));
        }
        if (!$product_id && !empty($item['product_id'])) {
            $local = wc_get_product(intval($item['product_id']));
            if ($local) $product_id = intval($item['product_id']);
        }

        $line->set_product_id($product_id);
        $line->set_variation_id(intval($item['variation_id'] ?? 0));

        $name = sanitize_text_field($item['name'] ?? '');
        if (!$name && $product_id) {
            $p = wc_get_product($product_id);
            if ($p) $name = $p->get_name();
        }
        if (!$name) $name = __('Imported Item', 'shopcentral');

        $line->set_name($name);
        $line->set_quantity(intval($item['quantity'] ?? 1));
        $line->set_subtotal(floatval($item['subtotal'] ?? 0));
        $line->set_total(floatval($item['total'] ?? 0));

        if (isset($item['tax_class'])) {
            $line->set_tax_class(sanitize_text_field($item['tax_class']));
        }
        if (isset($item['taxes']) && is_array($item['taxes'])) {
            $line->set_taxes($item['taxes']);
        }
        if (!empty($item['sku'])) {
            $line->add_meta_data('_child_sku', sanitize_text_field($item['sku']));
        }
        if (!empty($item['meta_data']) && is_array($item['meta_data'])) {
            foreach ($item['meta_data'] as $meta) {
                if (isset($meta['key'], $meta['value'])) {
                    $line->add_meta_data($meta['key'], $meta['value']);
                }
            }
        }

        $order->add_item($line);
    }

    /**
     * Add a coupon line — re-uses existing coupon on hub if available, otherwise creates one.
     */
    private function add_imported_coupon($order, $coupon)
    {
        $code = sanitize_text_field($coupon['code'] ?? '');
        if (!$code) return;

        $existing = new WC_Coupon($code);
        if (!$existing->get_id()) {
            $existing->set_code($code);
            $existing->set_description(sprintf(__('Imported from child store: %s', 'shopcentral'), $code));
            $existing->set_discount_type(in_array($coupon['discount_type'] ?? '', ['percent', 'fixed_cart', 'fixed_product']) ? $coupon['discount_type'] : 'fixed_cart');
            $existing->set_amount(floatval($coupon['amount'] ?? 0));
            $existing->set_individual_use(false);
            $existing->set_usage_limit(1);
            $existing->save();
        }

        $line = new WC_Order_Item_Coupon();
        $line->set_code($code);
        $line->set_discount(floatval($coupon['discount'] ?? 0));
        $line->set_discount_tax(floatval($coupon['discount_tax'] ?? 0));
        $order->add_item($line);
    }

    /**
     * Legacy stock-reduction path kept for stores that have order import turned off.
     */
    private function reduce_stock_only($params, $source_url)
    {
        if (empty($params['line_items']) || !is_array($params['line_items'])) return;

        foreach ($params['line_items'] as $item) {
            $sku = sanitize_text_field($item['sku'] ?? '');
            $qty = intval($item['quantity'] ?? 0);
            if (!$sku || $qty <= 0) continue;

            $product_id = wc_get_product_id_by_sku($sku);
            if (!$product_id) continue;

            $product = wc_get_product($product_id);
            if (!$product || !$product->managing_stock()) continue;

            global $shopcentral_exclude_url;
            $shopcentral_exclude_url = $source_url;
            wc_update_product_stock($product, $qty, 'decrease');
            $shopcentral_exclude_url = null;
        }
    }

    /**
     * Check if auto-sync is enabled in settings
     */
    private function is_sync_enabled()
    {
        return get_option('shopcentral_auto_sync', 'no') === 'yes';
    }

    /**
     * Sync product details when local product is updated
     */
    public function sync_product_details($product_id)
    {
        if (!$this->is_sync_enabled()) return;

        // Avoid infinite loops if this was triggered by a sync
        if (defined('SHOPCENTRAL_SYNCING_IN_PROGRESS') && SHOPCENTRAL_SYNCING_IN_PROGRESS) {
            return;
        }

        $product = wc_get_product($product_id);
        if (!$product || !$product->get_sku()) {
            return; // SKU is required for matching across stores
        }

        global $shopcentral_exclude_url;
        $exclude_url = !empty($shopcentral_exclude_url) ? $shopcentral_exclude_url : null;

        $this->push_to_remote_stores($product, 'all', $exclude_url);
    }

    /**
     * Sync product stock when local stock is changed
     */
    public function sync_product_stock($product, $exclude_url = null)
    {
        if (!$this->is_sync_enabled()) return;

        if (defined('SHOPCENTRAL_SYNCING_IN_PROGRESS') && SHOPCENTRAL_SYNCING_IN_PROGRESS) {
            return;
        }

        if (!is_object($product)) {
            $product = wc_get_product($product);
        }

        if (!$product || !$product->get_sku()) {
            return;
        }

        global $shopcentral_exclude_url;
        if (!$exclude_url && !empty($shopcentral_exclude_url)) {
            $exclude_url = $shopcentral_exclude_url;
        }

        $this->push_to_remote_stores($product, 'stock', $exclude_url);
    }

    /**
     * Sync stock reduction when an order is placed on the main site
     */
    public function sync_order_stock_reduction($order)
    {
        if (!$this->is_sync_enabled()) return;

        if (!is_object($order)) {
            $order = wc_get_order($order);
        }

        if (!$order) return;

        foreach ($order->get_items() as $item) {
            $product = $item->get_product();
            if ($product && $product->get_sku()) {
                $this->push_to_remote_stores($product, 'stock');
            }
        }
    }

    /**
     * Push product data to all connected remote stores
     */
    private function push_to_remote_stores($product, $type = 'all', $exclude_url = null)
    {
        global $wpdb;
        $table = $wpdb->prefix . 'shopcentral_stores';
        $current_url = home_url();

        $query = "SELECT * FROM $table WHERE url != %s";
        $args  = [$current_url];

        if ($exclude_url) {
            $query  .= ' AND url != %s';
            $args[] = $exclude_url;
        }

        $stores = $wpdb->get_results($wpdb->prepare($query, $args));

        if (empty($stores)) {
            return;
        }

        if (!defined('SHOPCENTRAL_SYNCING_IN_PROGRESS')) {
            define('SHOPCENTRAL_SYNCING_IN_PROGRESS', true);
        }

        $sku     = $product->get_sku();
        $payload = [];

        // --- Build payload ---
        if ($type === 'details' || $type === 'all') {
            $payload['name']              = $product->get_name();
            $payload['regular_price']     = $product->get_regular_price();
            $payload['sale_price']        = $product->get_sale_price();
            $payload['description']       = $product->get_description();
            $payload['short_description'] = $product->get_short_description();

            $image_ids = array_merge([$product->get_image_id()], $product->get_gallery_image_ids());
            $images    = [];
            foreach ($image_ids as $id) {
                if ($id) {
                    $url = wp_get_attachment_url($id);
                    if ($url) $images[] = ['src' => $url];
                }
            }
            if (!empty($images)) {
                $payload['images'] = $images;
            }

            $payload['meta_data'] = $this->prepare_product_meta_data($product);
        }

        if ($type === 'stock' || $type === 'all') {
            if (!is_object($product)) {
                $product = wc_get_product($product);
            }

            $payload['manage_stock']   = $product->managing_stock();
            $payload['stock_quantity'] = $product->get_stock_quantity();
            $payload['stock_status']   = $product->get_stock_status();

            if ($payload['stock_quantity'] === null && $payload['manage_stock']) {
                $payload['stock_quantity'] = get_post_meta($product->get_id(), '_stock', true);
            }
        }

        if (empty($payload)) {
            return;
        }

        if (!class_exists('ShopCentral_Store_API')) {
            require_once SHOPCENTRAL_PATH . 'includes/class-shopcentral-store-api.php';
        }
        $store_api = new ShopCentral_Store_API($this->namespace);

        foreach ($stores as $store) {
            $remote_products = $store_api->send_remote_wc_request(
                $store, 'wc/v3/products', 'GET', null, ['sku' => $sku]
            );

            if (is_wp_error($remote_products) || empty($remote_products) || !isset($remote_products[0]['id'])) {
                continue;
            }

            $remote_id = $remote_products[0]['id'];

            $store_api->send_remote_wc_request(
                $store, "wc/v3/products/$remote_id", 'PUT', $payload
            );
        }
    }

    /**
     * Collect and filter product meta_data using WC CRUD methods.
     * Only whitelisted meta keys are returned (via filter hook).
     *
     * @param WC_Product $product
     * @return array Array of ['key' => ..., 'value' => ...] pairs ready for WC API.
     */
    public function prepare_product_meta_data($product)
    {
        $raw_meta = $product->get_meta_data();
        $product_id = $product->get_id();

        $allowed_keys = apply_filters('shopcentral_allowed_product_meta', [], $product_id);

        if (empty($allowed_keys) || !is_array($allowed_keys)) {
            return [];
        }

        $allowed_map = array_fill_keys(array_map('strtolower', $allowed_keys), true);

        $prepared = [];
        foreach ($raw_meta as $meta_obj) {
            if (!is_object($meta_obj) || !method_exists($meta_obj, 'get_data')) {
                continue;
            }
            $data = $meta_obj->get_data();
            $key = $data['key'] ?? '';
            if (empty($key)) continue;

            if (!isset($allowed_map[strtolower($key)])) {
                continue;
            }

            $value = $data['value'] ?? '';

            $prepared[] = [
                'key'   => $key,
                'value' => $value,
            ];
        }

        return $prepared;
    }

    /**
     * Count whitelisted meta for batching control.
     *
     * @param WC_Product $product
     * @return int
     */
    public function count_whitelisted_meta($product)
    {
        return count($this->prepare_product_meta_data($product));
    }

    /**
     * Get or create a WordPress user (customer) by email.
     *
     * @param string $email       Customer email address
     * @param string $first_name  Billing first name
     * @param string $last_name   Billing last name
     * @param string $source_url  Child store URL (for tracking)
     * @return int|false          WP_User ID on success, false on failure or guest (empty email).
     */
    protected static $customer_id_cache = [];

    public static function flush_customer_cache() {
        self::$customer_id_cache = [];
    }

    public function get_or_create_customer( $email, $first_name = '', $last_name = '', $source_url = '' ) {
        $email = sanitize_email( trim( $email ) );

        if ( empty( $email ) || ! is_email( $email ) ) {
            $this->log_import( 'CUSTOMER_SKIP', 'No valid email provided (guest checkout).' );
            return false;
        }

        $cache_key = strtolower( $email );
        if ( isset( self::$customer_id_cache[ $cache_key ] ) ) {
            return self::$customer_id_cache[ $cache_key ];
        }

        $existing_user = get_user_by( 'email', $email );

        if ( $existing_user && $existing_user instanceof WP_User ) {
            $this->log_import( 'CUSTOMER_FOUND', "user_id={$existing_user->ID}, email={$email}" );
            self::$customer_id_cache[ $cache_key ] = intval( $existing_user->ID );
            return intval( $existing_user->ID );
        }

        $username = $this->generate_unique_username( $email );
        $password = wp_generate_password( 24, true, true );

        $user_data = array(
            'user_login' => $username,
            'user_email' => $email,
            'user_pass'  => $password,
            'first_name' => sanitize_text_field( $first_name ),
            'last_name'  => sanitize_text_field( $last_name ),
            'role'       => 'customer',
        );

        $user_id = wp_insert_user( $user_data );

        if ( is_wp_error( $user_id ) ) {
            $this->log_import( 'CUSTOMER_CREATE_ERROR', $user_id->get_error_message() . ", email={$email}" );
            return false;
        }

        update_user_meta( $user_id, '_shopcentral_imported_from', esc_url_raw( $source_url ) );
        update_user_meta( $user_id, '_shopcentral_imported_at', current_time( 'mysql' ) );
        update_user_meta( $user_id, '_shopcentral_password_reset', '1' );

        WC()->mailer()->emails['WC_Email_Customer_New_Account']->trigger( $user_id, $password, true );

        $this->log_import( 'CUSTOMER_CREATED', "user_id={$user_id}, email={$email}" );

        return intval( $user_id );
    }

    /**
     * Generate a unique WordPress username from an email address.
     * Appends a numeric suffix if the username already exists.
     *
     * @param string $email
     * @return string
     */
    private function generate_unique_username( $email ) {
        $parts   = explode( '@', $email );
        $base    = sanitize_user( $parts[0], true );
        $username = $base;

        if ( empty( $username ) ) {
            $username = 'customer_' . wp_rand( 10000, 99999 );
        }

        $suffix = 1;
        while ( username_exists( $username ) ) {
            if ( $suffix === 1 ) {
                $username = $base . wp_rand( 100, 999 );
            } else {
                $username = $base . $suffix;
            }
            $suffix++;
            if ( $suffix > 100 ) {
                $username = 'customer_' . wp_rand( 100000, 999999 );
                break;
            }
        }

        return $username;
    }
}
