<?php
declare(strict_types=1);

namespace App\Modules\Settings;

final class ShopproProductImageResolver
{
    public function __construct(
        private readonly ShopproApiClient $apiClient
    ) {
    }

    /**
     * @param array<string, mixed> $orderPayload
     * @param array<int, string> $cache
     * @return array<int, string>
     */
    public function resolveProductImagesForOrder(
        string $baseUrl,
        string $apiKey,
        int $timeout,
        array $orderPayload,
        array &$cache
    ): array {
        $result = [];
        $rawItems = $this->readPath($orderPayload, ['products', 'items', 'order_items']);
        if (!is_array($rawItems)) {
            return [];
        }

        foreach ($rawItems as $item) {
            if (!is_array($item)) {
                continue;
            }
            $productId = (int) $this->readPath($item, ['product_id']);
            $parentProductId = (int) $this->readPath($item, ['parent_product_id']);
            if ($productId <= 0 && $parentProductId <= 0) {
                continue;
            }

            foreach ([$productId, $parentProductId] as $candidateId) {
                if ($candidateId <= 0) {
                    continue;
                }
                if (!isset($cache[$candidateId])) {
                    $cache[$candidateId] = $this->fetchPrimaryProductImageUrl($baseUrl, $apiKey, $timeout, $candidateId) ?? '';
                }
            }

            if ($productId > 0) {
                $url = trim((string) ($cache[$productId] ?? ''));
                if ($url !== '') {
                    $result[$productId] = $url;
                }
            }
            if ($parentProductId > 0) {
                $url = trim((string) ($cache[$parentProductId] ?? ''));
                if ($url !== '') {
                    $result[$parentProductId] = $url;
                }
            }
        }

        return $result;
    }

    private function fetchPrimaryProductImageUrl(string $baseUrl, string $apiKey, int $timeout, int $productId): ?string
    {
        $response = $this->apiClient->fetchProductById($baseUrl, $apiKey, $timeout, $productId);
        if (($response['ok'] ?? false) !== true || !is_array($response['product'] ?? null)) {
            return null;
        }

        $product = (array) $response['product'];
        $images = $this->readPath($product, ['images', 'photos', 'gallery']);
        if (is_array($images)) {
            foreach ($images as $image) {
                if (is_array($image)) {
                    $src = trim((string) ($image['src'] ?? $image['url'] ?? $image['image'] ?? ''));
                    if ($src !== '') {
                        return $this->normalizeMediaUrl($baseUrl, $src);
                    }
                } elseif (is_string($image)) {
                    $src = trim($image);
                    if ($src !== '') {
                        return $this->normalizeMediaUrl($baseUrl, $src);
                    }
                }
            }
        }

        $flat = trim((string) $this->readPath($product, ['image', 'image_url', 'photo', 'photo_url', 'img', 'img_url']));
        if ($flat !== '') {
            return $this->normalizeMediaUrl($baseUrl, $flat);
        }

        return null;
    }

    private function normalizeMediaUrl(string $baseUrl, string $value): string
    {
        $trimmed = trim($value);
        if ($trimmed === '') {
            return '';
        }
        if (str_starts_with($trimmed, '//')) {
            return 'https:' . $trimmed;
        }
        if (preg_match('#^https?://#i', $trimmed) === 1) {
            return $trimmed;
        }

        return rtrim($baseUrl, '/') . '/' . ltrim($trimmed, '/');
    }

    private function readPath(mixed $payload, array $paths): mixed
    {
        foreach ($paths as $path) {
            $value = $this->readSinglePath($payload, (string) $path);
            if ($value !== null && $value !== '') {
                return $value;
            }
        }

        return null;
    }

    private function readSinglePath(mixed $payload, string $path): mixed
    {
        if ($path === '') {
            return null;
        }

        $segments = explode('.', $path);
        $current = $payload;
        foreach ($segments as $segment) {
            if (!is_array($current) || !array_key_exists($segment, $current)) {
                return null;
            }
            $current = $current[$segment];
        }

        return $current;
    }
}
