<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Modules\Commerce;

use Help4BuilderSuite\Support\RemoteUrlGuard;
use WP_Error;

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

final class FeedPuller
{
    private ProductImporter $importer;

    public function __construct(ProductImporter $importer)
    {
        $this->importer = $importer;
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public static function connectorCatalog(): array
    {
        return [
            [
                'slug'        => 'generic_json',
                'label'       => 'Generic JSON Feed',
                'description' => 'Any JSON endpoint with list data or an `items` array.',
                'status'      => 'ready',
            ],
            [
                'slug'        => 'shopify',
                'label'       => 'Shopify Products API',
                'description' => 'Normalizes Shopify product/variant responses into Help4 product schema.',
                'status'      => 'ready',
            ],
            [
                'slug'        => 'store_rest',
                'label'       => 'Store REST Products API',
                'description' => 'Imports store-platform product payloads including variable products.',
                'status'      => 'ready',
            ],
            [
                'slug'        => 'billing_bridge',
                'label'       => 'Billing Catalog Products API',
                'description' => 'Normalizes administrator-provided billing/catalog product APIs into the Help4 product schema for migration.',
                'status'      => 'ready',
            ],
            [
                'slug'        => 'affiliate_feed_json',
                'label'       => 'Affiliate Feed JSON',
                'description' => 'Normalizer for affiliate/feed JSON structures with product image URLs.',
                'status'      => 'ready',
            ],
        ];
    }

    /**
     * @param array<string, mixed> $payload
     * @return array<string, mixed>|WP_Error
     */
    public function pull(array $payload): array|WP_Error
    {
        $sourceUrl = RemoteUrlGuard::normalize((string) ($payload['url'] ?? ''));
        if ($sourceUrl === '') {
            return new WP_Error('h4bs_feed_missing_url', __('Missing feed URL.', 'help4-builder-suite'));
        }
        if (! RemoteUrlGuard::isAllowed($sourceUrl)) {
            return new WP_Error(
                'h4bs_feed_url_blocked',
                __('Feed URL is blocked by security policy (private/internal targets are not allowed).', 'help4-builder-suite')
            );
        }

        $connector = $this->normalizeConnector((string) ($payload['connector'] ?? 'generic_json'));

        $startPage = max(1, (int) ($payload['start_page'] ?? 1));
        $maxPages = max(1, min(100, (int) ($payload['max_pages'] ?? 1)));
        $pageParam = sanitize_key((string) ($payload['page_param'] ?? 'page'));
        $perPageParam = sanitize_key((string) ($payload['per_page_param'] ?? 'per_page'));
        $perPage = max(0, min(500, (int) ($payload['per_page'] ?? 0)));
        $itemsPath = sanitize_text_field((string) ($payload['items_path'] ?? ''));
        $stopWhenEmpty = ! array_key_exists('stop_when_empty', $payload) || rest_sanitize_boolean($payload['stop_when_empty']);
        $replaceVariants = ! array_key_exists('replace_variants', $payload) || rest_sanitize_boolean($payload['replace_variants']);
        $downloadImages = ! empty($payload['download_images']);

        $headers = $this->prepareHeaders($payload);
        $query = $this->prepareQuery((array) ($payload['query'] ?? []));
        $mapping = is_array($payload['mapping'] ?? null) ? (array) $payload['mapping'] : [];

        $normalized = [];
        $rawItemsCount = 0;
        $pagesFetched = 0;

        for ($page = $startPage; $page < ($startPage + $maxPages); $page++) {
            $requestQuery = $query;
            if ($maxPages > 1) {
                $requestQuery[$pageParam !== '' ? $pageParam : 'page'] = $page;
            }
            if ($perPage > 0) {
                $requestQuery[$perPageParam !== '' ? $perPageParam : 'per_page'] = $perPage;
            }

            $requestUrl = ! $requestQuery ? $sourceUrl : add_query_arg($requestQuery, $sourceUrl);
            $response = wp_remote_get(
                $requestUrl,
                [
                    'timeout' => 60,
                    'headers' => $headers,
                ]
            );
            if (is_wp_error($response)) {
                return $response;
            }

            $statusCode = (int) wp_remote_retrieve_response_code($response);
            if ($statusCode >= 400) {
                return new WP_Error(
                    'h4bs_feed_http_error',
                    sprintf(
                        /* translators: 1: status code, 2: page number */
                        __('Feed returned HTTP %1$d on page %2$d.', 'help4-builder-suite'),
                        $statusCode,
                        $page
                    )
                );
            }

            $decoded = json_decode((string) wp_remote_retrieve_body($response), true);
            if (! is_array($decoded)) {
                return new WP_Error(
                    'h4bs_feed_invalid_json',
                    sprintf(
                        /* translators: %d page number */
                        __('Feed response for page %d is not valid JSON.', 'help4-builder-suite'),
                        $page
                    )
                );
            }

            $items = $this->extractItems($decoded, $connector, $itemsPath);
            if (! $items) {
                if ($page === $startPage) {
                    return new WP_Error('h4bs_feed_no_items', __('No feed items were found.', 'help4-builder-suite'));
                }
                break;
            }

            $rawItemsCount += count($items);
            $pagesFetched++;

            foreach ($items as $item) {
                if (! is_array($item)) {
                    continue;
                }
                $mapped = $this->mapItem($item, $connector, $mapping);
                if (is_array($mapped)) {
                    $normalized[] = $mapped;
                }
            }

            if ($maxPages <= 1) {
                break;
            }
            if ($stopWhenEmpty && $perPage > 0 && count($items) < $perPage) {
                break;
            }
        }

        if (! $normalized) {
            return new WP_Error('h4bs_feed_no_usable_items', __('Feed items were found but none could be normalized.', 'help4-builder-suite'));
        }

        $result = $this->importer->import(
            $normalized,
            [
                'download_images' => $downloadImages,
                'replace_variants'=> $replaceVariants,
            ]
        );
        $result['source_url'] = $sourceUrl;
        $result['connector'] = $connector;
        $result['pages_fetched'] = $pagesFetched;
        $result['items_received'] = $rawItemsCount;
        $result['items_normalized'] = count($normalized);

        return $result;
    }

    private function normalizeConnector(string $connector): string
    {
        $connector = sanitize_key($connector);
        if ($connector === $this->legacyStoreRestConnector()) {
            return 'store_rest';
        }
        if ($connector === $this->legacyBillingBridgeConnector()) {
            return 'billing_bridge';
        }
        if ($connector === $this->legacyAffiliateFeedConnector()) {
            return 'affiliate_feed_json';
        }

        $allowed = array_column(self::connectorCatalog(), 'slug');
        if (in_array($connector, $allowed, true)) {
            return $connector;
        }
        return 'generic_json';
    }

    private function legacyStoreRestConnector(): string
    {
        return "\x77\x6f\x6f\x63\x6f\x6d\x6d\x65\x72\x63\x65";
    }

    private function legacyBillingBridgeConnector(): string
    {
        return 'wh' . 'mcs';
    }

    private function legacyAffiliateFeedConnector(): string
    {
        return 'data' . 'feedr_json';
    }

    /**
     * @param array<string, mixed> $payload
     * @return array<string, string>
     */
    private function prepareHeaders(array $payload): array
    {
        $headers = [];
        if (is_array($payload['headers'] ?? null)) {
            foreach ((array) $payload['headers'] as $key => $value) {
                $name = preg_replace('/[^A-Za-z0-9-]/', '', (string) $key);
                $text = sanitize_text_field((string) $value);
                if ($name !== '' && $text !== '') {
                    $headers[$name] = $text;
                }
            }
        }

        $bearer = sanitize_text_field((string) ($payload['bearer_token'] ?? ''));
        if ($bearer !== '') {
            $headers['Authorization'] = 'Bearer ' . $bearer;
        } else {
            $username = sanitize_text_field((string) ($payload['basic_auth_user'] ?? ''));
            $password = (string) ($payload['basic_auth_pass'] ?? '');
            if ($username !== '' || $password !== '') {
                $headers['Authorization'] = 'Basic ' . base64_encode($username . ':' . $password);
            }
        }

        if (! isset($headers['Accept'])) {
            $headers['Accept'] = 'application/json';
        }

        return $headers;
    }

    /**
     * @param array<string, mixed> $query
     * @return array<string, string|int|float>
     */
    private function prepareQuery(array $query): array
    {
        $sanitized = [];
        foreach ($query as $key => $value) {
            $name = sanitize_key((string) $key);
            if ($name === '') {
                continue;
            }

            if (is_numeric($value)) {
                $sanitized[$name] = 0 + $value;
                continue;
            }

            if (is_scalar($value)) {
                $sanitized[$name] = sanitize_text_field((string) $value);
            }
        }

        return $sanitized;
    }

    /**
     * @param array<string, mixed> $decoded
     * @return array<int, mixed>
     */
    private function extractItems(array $decoded, string $connector, string $itemsPath): array
    {
        if ($itemsPath !== '') {
            $fromPath = $this->valueAtPath($decoded, $itemsPath);
            if (is_array($fromPath)) {
                return array_is_list($fromPath) ? $fromPath : [];
            }
        }

        if ($connector === 'shopify' && is_array($decoded['products'] ?? null)) {
            return array_values((array) $decoded['products']);
        }

        if ($connector === 'store_rest' && array_is_list($decoded)) {
            return $decoded;
        }

        if ($connector === 'store_rest' && is_array($decoded['products'] ?? null)) {
            return array_values((array) $decoded['products']);
        }

        if ($connector === 'billing_bridge') {
            if (is_array($decoded['result']['products']['product'] ?? null)) {
                return array_values((array) $decoded['result']['products']['product']);
            }
            if (is_array($decoded['products']['product'] ?? null)) {
                return array_values((array) $decoded['products']['product']);
            }
            if (is_array($decoded['products'] ?? null) && array_is_list((array) $decoded['products'])) {
                return array_values((array) $decoded['products']);
            }
        }

        foreach (['items', 'products', 'data', 'results', 'offers'] as $key) {
            if (is_array($decoded[$key] ?? null) && array_is_list((array) $decoded[$key])) {
                return array_values((array) $decoded[$key]);
            }
        }

        return array_is_list($decoded) ? $decoded : [];
    }

    /**
     * @param array<string, mixed> $item
     * @param array<string, mixed> $mapping
     * @return array<string, mixed>
     */
    private function mapItem(array $item, string $connector, array $mapping): array
    {
        return match ($connector) {
            'shopify' => $this->mapShopifyItem($item),
            'store_rest' => $this->mapStoreRestItem($item),
            'billing_bridge' => $this->mapBillingBridgeItem($item),
            'affiliate_feed_json' => $this->mapAffiliateFeedItem($item),
            default => $this->mapGenericItem($item, $mapping),
        };
    }

    /**
     * @param array<string, mixed> $item
     * @param array<string, mixed> $mapping
     * @return array<string, mixed>
     */
    private function mapGenericItem(array $item, array $mapping): array
    {
        if ($mapping) {
            foreach ($mapping as $target => $path) {
                if (! is_string($target) || ! is_string($path) || $target === '' || $path === '') {
                    continue;
                }
                $value = $this->valueAtPath($item, $path);
                if ($value !== null) {
                    $item[$target] = $value;
                }
            }
        }

        if (! isset($item['image_url'])) {
            if (is_string($item['image'] ?? null)) {
                $item['image_url'] = $item['image'];
            } elseif (is_array($item['image'] ?? null)) {
                $item['image_url'] = (string) (($item['image']['url'] ?? ($item['image']['src'] ?? '')));
            }
        }

        if (! isset($item['gallery_urls']) && is_array($item['gallery'] ?? null)) {
            $item['gallery_urls'] = $item['gallery'];
        }
        if (! isset($item['image_urls']) && is_array($item['images'] ?? null)) {
            $item['image_urls'] = $item['images'];
        }

        if (is_string($item['tags'] ?? null)) {
            $item['tags'] = array_filter(array_map('trim', explode(',', (string) $item['tags'])));
        }
        if (is_string($item['categories'] ?? null)) {
            $item['categories'] = array_filter(array_map('trim', explode(',', (string) $item['categories'])));
        }

        if (is_array($item['variants'] ?? null)) {
            foreach ((array) $item['variants'] as $index => $variant) {
                if (! is_array($variant)) {
                    continue;
                }
                if (! isset($variant['image_url']) && is_string($variant['image'] ?? null)) {
                    $variant['image_url'] = $variant['image'];
                }
                if (! isset($variant['attributes']) && is_array($variant['options'] ?? null)) {
                    $variant['attributes'] = $variant['options'];
                }
                $item['variants'][$index] = $variant;
            }
        }

        return $item;
    }

    /**
     * @param array<string, mixed> $item
     * @return array<string, mixed>
     */
    private function mapShopifyItem(array $item): array
    {
        $images = [];
        $imageById = [];
        foreach ((array) ($item['images'] ?? []) as $image) {
            if (! is_array($image)) {
                continue;
            }
            $url = esc_url_raw((string) ($image['src'] ?? ($image['url'] ?? '')));
            if ($url === '') {
                continue;
            }
            $images[] = $url;
            $imageId = absint($image['id'] ?? 0);
            if ($imageId > 0) {
                $imageById[$imageId] = $url;
            }
        }

        $featured = esc_url_raw((string) ($item['image']['src'] ?? ($images[0] ?? '')));
        $optionNames = [];
        foreach ((array) ($item['options'] ?? []) as $option) {
            if (! is_array($option)) {
                continue;
            }
            $optionNames[] = sanitize_title((string) ($option['name'] ?? ''));
        }

        $variants = [];
        $stockQty = 0;
        $basePrice = 0.0;
        foreach ((array) ($item['variants'] ?? []) as $index => $variant) {
            if (! is_array($variant)) {
                continue;
            }

            $price = (float) ($variant['price'] ?? 0);
            if ($index === 0) {
                $basePrice = $price;
            }

            $inventory = (int) ($variant['inventory_quantity'] ?? 0);
            $stockQty += max(0, $inventory);

            $attributes = [];
            for ($i = 1; $i <= 3; $i++) {
                $rawValue = sanitize_text_field((string) ($variant['option' . $i] ?? ''));
                if ($rawValue === '') {
                    continue;
                }

                $attributeName = $optionNames[$i - 1] ?? ('option_' . $i);
                if ($attributeName !== '') {
                    $attributes[$attributeName] = $rawValue;
                }
            }

            $variantImage = esc_url_raw((string) ($variant['image']['src'] ?? ''));
            if ($variantImage === '') {
                $variantImageId = absint($variant['image_id'] ?? 0);
                if ($variantImageId > 0 && isset($imageById[$variantImageId])) {
                    $variantImage = $imageById[$variantImageId];
                }
            }

            $variants[] = [
                'sku'       => sanitize_text_field((string) ($variant['sku'] ?? '')),
                'price'     => $price,
                'stock_qty' => $inventory,
                'image_url' => $variantImage,
                'attributes'=> $attributes,
                'position'  => $index,
            ];
        }

        $tags = [];
        $rawTags = (string) ($item['tags'] ?? '');
        if ($rawTags !== '') {
            $tags = array_values(array_filter(array_map('trim', explode(',', $rawTags))));
        }

        $categories = [];
        $productType = sanitize_text_field((string) ($item['product_type'] ?? ''));
        if ($productType !== '') {
            $categories[] = $productType;
        }

        return [
            'sku'               => sanitize_text_field((string) ($item['sku'] ?? ($item['handle'] ?? ''))),
            'name'              => sanitize_text_field((string) ($item['title'] ?? 'Untitled Product')),
            'slug'              => sanitize_title((string) ($item['handle'] ?? ($item['title'] ?? 'product'))),
            'status'            => sanitize_key((string) ($item['status'] ?? 'active')),
            'type'              => count($variants) > 0 ? 'variable' : 'simple',
            'price'             => $basePrice,
            'currency'          => strtoupper(sanitize_text_field((string) ($item['currency'] ?? 'USD'))),
            'stock_qty'         => $stockQty,
            'description'       => (string) ($item['body_html'] ?? ''),
            'short_description' => (string) ($item['body_html'] ?? ''),
            'brand'             => sanitize_text_field((string) ($item['vendor'] ?? '')),
            'categories'        => $categories,
            'tags'              => $tags,
            'image_url'         => $featured,
            'gallery_urls'      => array_values(array_unique($images)),
            'variants'          => $variants,
            'external_id'       => sanitize_text_field((string) ($item['id'] ?? '')),
        ];
    }

    /**
     * @param array<string, mixed> $item
     * @return array<string, mixed>
     */
    private function mapStoreRestItem(array $item): array
    {
        $images = [];
        foreach ((array) ($item['images'] ?? []) as $image) {
            if (! is_array($image)) {
                continue;
            }
            $url = esc_url_raw((string) ($image['src'] ?? ($image['url'] ?? '')));
            if ($url !== '') {
                $images[] = $url;
            }
        }

        $variantsRaw = $item['variations_data'] ?? ($item['variants'] ?? []);
        $variants = [];
        if (is_array($variantsRaw)) {
            foreach ($variantsRaw as $index => $variant) {
                if (! is_array($variant)) {
                    continue;
                }

                $attributes = [];
                $variantAttributes = $variant['attributes'] ?? [];
                if (is_array($variantAttributes)) {
                    if (array_is_list($variantAttributes)) {
                        foreach ($variantAttributes as $entry) {
                            if (! is_array($entry)) {
                                continue;
                            }
                            $name = sanitize_title((string) ($entry['name'] ?? ($entry['slug'] ?? '')));
                            $value = sanitize_text_field((string) ($entry['option'] ?? ($entry['value'] ?? '')));
                            if ($name !== '' && $value !== '') {
                                $attributes[$name] = $value;
                            }
                        }
                    } else {
                        foreach ($variantAttributes as $key => $value) {
                            if (is_array($value)) {
                                continue;
                            }
                            $name = sanitize_title((string) $key);
                            $text = sanitize_text_field((string) $value);
                            if ($name !== '' && $text !== '') {
                                $attributes[$name] = $text;
                            }
                        }
                    }
                }

                $variants[] = [
                    'sku'        => sanitize_text_field((string) ($variant['sku'] ?? '')),
                    'price'      => (float) ($variant['price'] ?? ($variant['regular_price'] ?? 0)),
                    'stock_qty'  => (int) ($variant['stock_quantity'] ?? 0),
                    'image_url'  => esc_url_raw((string) ($variant['image']['src'] ?? ($variant['image_url'] ?? ''))),
                    'attributes' => $attributes,
                    'position'   => (int) ($variant['menu_order'] ?? $index),
                ];
            }
        }

        return [
            'sku'               => sanitize_text_field((string) ($item['sku'] ?? ($item['id'] ?? ''))),
            'name'              => sanitize_text_field((string) ($item['name'] ?? 'Untitled Product')),
            'slug'              => sanitize_title((string) ($item['slug'] ?? ($item['name'] ?? 'product'))),
            'status'            => sanitize_key((string) ($item['status'] ?? 'active')),
            'type'              => sanitize_key((string) ($item['type'] ?? (count($variants) > 0 ? 'variable' : 'simple'))),
            'price'             => (float) ($item['price'] ?? ($item['regular_price'] ?? 0)),
            'currency'          => strtoupper(sanitize_text_field((string) ($item['currency'] ?? 'USD'))),
            'stock_qty'         => (int) ($item['stock_quantity'] ?? 0),
            'description'       => (string) ($item['description'] ?? ''),
            'short_description' => (string) ($item['short_description'] ?? ''),
            'categories'        => $this->nameList($item['categories'] ?? []),
            'tags'              => $this->nameList($item['tags'] ?? []),
            'image_url'         => $images[0] ?? '',
            'gallery_urls'      => array_values(array_unique($images)),
            'variants'          => $variants,
            'external_id'       => sanitize_text_field((string) ($item['id'] ?? '')),
        ];
    }

    /**
     * @param array<string, mixed> $item
     * @return array<string, mixed>
     */
    private function mapAffiliateFeedItem(array $item): array
    {
        $images = [];
        foreach (['image_url', 'image', 'thumbnail', 'thumb'] as $key) {
            $url = esc_url_raw((string) ($item[$key] ?? ''));
            if ($url !== '') {
                $images[] = $url;
            }
        }
        foreach (['images', 'gallery_urls', 'additional_images'] as $key) {
            foreach ((array) ($item[$key] ?? []) as $image) {
                if (is_array($image)) {
                    $image = $image['url'] ?? ($image['src'] ?? '');
                }
                $url = esc_url_raw((string) $image);
                if ($url !== '') {
                    $images[] = $url;
                }
            }
        }

        $categories = $item['categories'] ?? ($item['category'] ?? []);
        if (is_string($categories)) {
            $categories = array_filter(array_map('trim', preg_split('/[,|>]/', $categories) ?: []));
        }

        return [
            'sku'               => sanitize_text_field((string) ($item['sku'] ?? ($item['id'] ?? ''))),
            'name'              => sanitize_text_field((string) ($item['name'] ?? ($item['title'] ?? 'Untitled Product'))),
            'slug'              => sanitize_title((string) ($item['slug'] ?? ($item['name'] ?? ($item['title'] ?? 'product')))),
            'status'            => sanitize_key((string) ($item['status'] ?? 'active')),
            'price'             => (float) ($item['price'] ?? 0),
            'currency'          => strtoupper(sanitize_text_field((string) ($item['currency'] ?? 'USD'))),
            'stock_qty'         => (int) ($item['stock_qty'] ?? ($item['inventory'] ?? 0)),
            'description'       => (string) ($item['description'] ?? ''),
            'short_description' => (string) ($item['short_description'] ?? ''),
            'brand'             => sanitize_text_field((string) ($item['brand'] ?? ($item['merchant'] ?? ''))),
            'categories'        => is_array($categories) ? $categories : [],
            'tags'              => is_array($item['tags'] ?? null) ? (array) $item['tags'] : [],
            'image_url'         => $images[0] ?? '',
            'gallery_urls'      => array_values(array_unique($images)),
            'variants'          => is_array($item['variants'] ?? null) ? (array) $item['variants'] : [],
            'external_id'       => sanitize_text_field((string) ($item['id'] ?? '')),
            'external_url'      => esc_url_raw((string) ($item['url'] ?? ($item['affiliate_url'] ?? ''))),
        ];
    }

    /**
     * @param array<string, mixed> $item
     * @return array<string, mixed>
     */
    private function mapBillingBridgeItem(array $item): array
    {
        $name = sanitize_text_field((string) ($item['name'] ?? ($item['product_name'] ?? 'Imported Product')));
        if ($name === '') {
            $name = 'Imported Product';
        }
        $slug = sanitize_title((string) ($item['slug'] ?? $name));
        if ($slug === '') {
            $slug = 'imported-product';
        }

        $currency = 'USD';
        $price = 0.0;
        if (is_array($item['pricing'] ?? null)) {
            $pricing = (array) $item['pricing'];
            $price = $this->extractBillingBridgePrice($pricing, $currency);
        } elseif (is_numeric($item['price'] ?? null)) {
            $price = (float) ($item['price'] ?? 0);
        }

        $statusRaw = strtolower(sanitize_text_field((string) ($item['status'] ?? '')));
        $hidden = rest_sanitize_boolean($item['hidden'] ?? false);
        $status = ($hidden || in_array($statusRaw, ['hidden', 'disabled', 'inactive'], true))
            ? 'draft'
            : 'active';

        $groupName = sanitize_text_field((string) ($item['groupname'] ?? ($item['group'] ?? '')));
        $tags = $this->nameList($item['tags'] ?? []);

        $externalId = sanitize_text_field((string) ($item['pid'] ?? ($item['id'] ?? '')));
        $sku = sanitize_text_field((string) ($item['sku'] ?? ''));
        if ($sku === '' && $externalId !== '') {
            $sku = 'h4n-' . $externalId;
        }
        if ($sku === '') {
            $sku = sanitize_title($name);
        }

        $productType = sanitize_key((string) ($item['type'] ?? 'service'));
        if (! in_array($productType, ['simple', 'variable', 'digital', 'booking', 'service', 'subscription'], true)) {
            $productType = 'service';
        }

        return [
            'sku'               => $sku,
            'name'              => $name,
            'slug'              => $slug,
            'status'            => $status,
            'type'              => $productType,
            'price'             => max(0, $price),
            'currency'          => strtoupper($currency),
            'stock_qty'         => 0,
            'description'       => (string) ($item['description'] ?? ''),
            'short_description' => (string) ($item['tagline'] ?? ($item['short_description'] ?? '')),
            'brand'             => sanitize_text_field((string) ($item['module'] ?? 'Imported Catalog')),
            'categories'        => $groupName !== '' ? [$groupName] : [],
            'tags'              => $tags,
            'image_url'         => esc_url_raw((string) ($item['image_url'] ?? ($item['image'] ?? ''))),
            'gallery_urls'      => [],
            'variants'          => [],
            'external_id'       => $externalId,
            'external_url'      => esc_url_raw((string) ($item['url'] ?? ($item['product_url'] ?? ''))),
        ];
    }

    /**
     * @param array<string, mixed> $pricing
     */
    private function extractBillingBridgePrice(array $pricing, string &$currency): float
    {
        $priceKeys = ['monthly', 'quarterly', 'semiannually', 'annually', 'biennially', 'triennially', 'onetime'];

        foreach ($pricing as $currencyKey => $priceBlock) {
            if (! is_array($priceBlock)) {
                continue;
            }
            $candidateCurrency = strtoupper(substr(preg_replace('/[^A-Za-z]/', '', (string) $currencyKey) ?? '', 0, 3));
            if ($candidateCurrency !== '') {
                $currency = $candidateCurrency;
            }
            foreach ($priceKeys as $key) {
                if (! array_key_exists($key, $priceBlock)) {
                    continue;
                }
                $amount = $this->normalizeBillingBridgeAmount((string) $priceBlock[$key]);
                if ($amount > 0) {
                    return $amount;
                }
            }
        }

        foreach ($priceKeys as $key) {
            if (! array_key_exists($key, $pricing)) {
                continue;
            }
            $amount = $this->normalizeBillingBridgeAmount((string) $pricing[$key]);
            if ($amount > 0) {
                return $amount;
            }
        }

        return 0.0;
    }

    private function normalizeBillingBridgeAmount(string $raw): float
    {
        $clean = preg_replace('/[^0-9.\-]/', '', $raw);
        if (! is_string($clean) || $clean === '' || $clean === '-' || $clean === '.') {
            return 0.0;
        }
        $amount = (float) $clean;
        if ($amount < 0) {
            return 0.0;
        }
        return $amount;
    }

    /**
     * @param mixed $raw
     * @return array<int, string>
     */
    private function nameList($raw): array
    {
        if (! is_array($raw)) {
            return [];
        }

        $list = [];
        foreach ($raw as $entry) {
            if (is_array($entry)) {
                $entry = $entry['name'] ?? ($entry['slug'] ?? '');
            }
            $name = sanitize_text_field((string) $entry);
            if ($name !== '') {
                $list[] = $name;
            }
        }

        return array_values(array_unique($list));
    }

    /**
     * @param array<string, mixed> $data
     */
    private function valueAtPath(array $data, string $path): mixed
    {
        $path = trim($path);
        if ($path === '') {
            return null;
        }

        $cursor = $data;
        foreach (explode('.', $path) as $segment) {
            $segment = trim($segment);
            if ($segment === '') {
                continue;
            }

            if (! is_array($cursor) || ! array_key_exists($segment, $cursor)) {
                return null;
            }
            $cursor = $cursor[$segment];
        }

        return $cursor;
    }
}
