<?php

declare(strict_types=1);

final class MyronMarketplaceCatalogClient
{
    public function __construct(
        private readonly string $baseUrl = '',
        private readonly int $timeoutSeconds = 3,
    ) {
    }

    /**
     * @return array{ok:bool,items:list<array<string,mixed>>,source:string,error:string}
     */
    public function list(array $filters = []): array
    {
        $fixture = trim((string) getenv('MYRON_MARKETPLACE_CATALOG_FIXTURE'));
        if ($fixture !== '' && is_file($fixture)) {
            return $this->decodePayload((string) file_get_contents($fixture), 'fixture');
        }

        $inlineJson = trim((string) getenv('MYRON_MARKETPLACE_CATALOG_JSON'));
        if ($inlineJson !== '') {
            return $this->decodePayload($inlineJson, 'inline');
        }

        if ($this->outboundDisabled()) {
            return $this->emptyFailure('outbound_disabled');
        }

        $url = $this->catalogUrl($filters);
        if ($url === '') {
            return $this->emptyFailure('marketplace_url_unavailable');
        }

        $context = stream_context_create([
            'http' => [
                'method' => 'GET',
                'timeout' => max(1, $this->timeoutSeconds),
                'header' => "Accept: application/json\r\n",
            ],
        ]);
        $json = @file_get_contents($url, false, $context);
        if (!is_string($json) || $json === '') {
            return $this->emptyFailure('catalog_unreachable');
        }

        return $this->decodePayload($json, 'remote');
    }

    public function checkoutUrl(string $skuId, string $returnUrl, string $billingPeriod = 'monthly'): string
    {
        $baseUrl = $this->resolvedBaseUrl();
        if ($baseUrl === '') {
            return '';
        }

        return $baseUrl . '/checkout.php?' . http_build_query([
            'skuId' => $skuId,
            'billingPeriod' => in_array($billingPeriod, ['monthly', 'annual'], true) ? $billingPeriod : 'monthly',
            'returnUrl' => $returnUrl,
        ]);
    }

    private function catalogUrl(array $filters): string
    {
        $baseUrl = $this->resolvedBaseUrl();
        if ($baseUrl === '') {
            return '';
        }

        $query = [];
        foreach (['compatibility', 'type', 'category', 'jtbd', 'q'] as $key) {
            $value = trim((string) ($filters[$key] ?? ''));
            if ($value !== '') {
                $query[$key] = $value;
            }
        }

        return $baseUrl . '/api/v1/catalog.php' . ($query === [] ? '' : '?' . http_build_query($query));
    }

    private function resolvedBaseUrl(): string
    {
        $url = trim($this->baseUrl);
        if ($url === '') {
            $url = trim((string) getenv('MYRON_MARKETPLACE_URL'));
        }
        if ($url === '') {
            $url = 'https://market.myroncms.com';
        }
        if (!preg_match('#^https?://#i', $url)) {
            return '';
        }

        return rtrim($url, '/');
    }

    /**
     * @return array{ok:bool,items:list<array<string,mixed>>,source:string,error:string}
     */
    private function decodePayload(string $json, string $source): array
    {
        $payload = json_decode($json, true);
        if (!is_array($payload)) {
            return $this->emptyFailure('catalog_json_invalid', $source);
        }

        $rawItems = is_array($payload['items'] ?? null) ? $payload['items'] : [];
        $items = [];
        foreach ($rawItems as $item) {
            if (!is_array($item)) {
                continue;
            }
            $skuId = trim((string) ($item['skuId'] ?? $item['sku_id'] ?? ''));
            $displayName = trim((string) ($item['displayName'] ?? $item['display_name'] ?? $item['slug'] ?? ''));
            if ($skuId === '' || $displayName === '') {
                continue;
            }
            $items[] = [
                'skuId' => $skuId,
                'slug' => trim((string) ($item['slug'] ?? $skuId)),
                'displayName' => $displayName,
                'summary' => trim((string) ($item['summary'] ?? '')),
                'targetType' => trim((string) ($item['targetType'] ?? $item['target_type'] ?? 'module-bundle')),
                'category' => trim((string) ($item['category'] ?? '')),
                'jtbd' => trim((string) ($item['jtbd'] ?? '')),
                'prices' => is_array($item['prices'] ?? null) ? $item['prices'] : [],
                'compatibility' => is_array($item['compatibility'] ?? null) ? $item['compatibility'] : [],
                'capabilities' => is_array($item['capabilities'] ?? null) ? $item['capabilities'] : [],
            ];
        }

        return ['ok' => true, 'items' => $items, 'source' => $source, 'error' => ''];
    }

    /**
     * @return array{ok:bool,items:list<array<string,mixed>>,source:string,error:string}
     */
    private function emptyFailure(string $error, string $source = ''): array
    {
        return ['ok' => false, 'items' => [], 'source' => $source, 'error' => $error];
    }

    private function outboundDisabled(): bool
    {
        $raw = strtolower(trim((string) getenv('MYRON_NO_OUTBOUND')));
        return in_array($raw, ['1', 'true', 'yes', 'on'], true);
    }
}
