<?php

declare(strict_types=1);

namespace EasyChat\Library\Update;

use EasyChat\Library\Http\ExternalHttpClient;
use EasyChat\Model\Setting;

final class SignedUpdateCatalog
{
    private const PRODUCTION_ENDPOINT = 'https://api.easychat24.ru/api/v1/updates/latest';
    private const STAGE_ENDPOINT = 'https://stage.api.easychat24.ru/api/v1/updates/latest';
     
     
     
    private const FRESH_SECONDS = 300;
    private const STALE_FALLBACK_SECONDS = 259200;

    private $registry;
    private ExternalHttpClient $http;
    private ReleaseManifestVerifier $verifier;
    private string $endpoint;

    public function __construct(
        $registry,
        ?ExternalHttpClient $http = null,
        ?ReleaseManifestVerifier $verifier = null,
        ?string $endpoint = null
    )
    {
        $this->registry = $registry;
        $this->http = $http ?: new ExternalHttpClient($registry);
        $this->verifier = $verifier ?: new ReleaseManifestVerifier();
        $this->endpoint = $this->resolveEndpoint($endpoint);
    }

     
    public function latest(bool $forceRefresh = false): array
    {
        $settings = new Setting($this->registry);
        $cachedAt = (int)$settings->get('signed_update_manifest_cached_at', '0');
        $cachedRaw = (string)$settings->get('signed_update_manifest_json', '');
        $cached = $this->decodeAndVerify($cachedRaw);
        $age = $cachedAt > 0 && $cachedAt <= time() ? time() - $cachedAt : PHP_INT_MAX;

        if (!$forceRefresh && $cached !== null && $age <= self::FRESH_SECONDS) {
            return ['success' => true, 'payload' => $cached, 'from_cache' => true, 'stale' => false];
        }

        $response = $this->http->request('GET', $this->endpoint, [
            'timeout' => 10,
            'connect_timeout' => 4,
            'trust_profile' => 'easychat_gateway',
            'allow_tls_fallback' => true,
            'headers' => ['Accept: application/json'],
        ]);
        $raw = (string)($response['raw'] ?? '');
        if (!empty($response['transport_ok'])
            && (int)($response['http_code'] ?? 0) === 200
            && strlen($raw) > 0
            && strlen($raw) <= 1024 * 1024
        ) {
            $verified = $this->decodeAndVerify($raw);
            if ($verified !== null) {
                $settings->setMany([
                    'signed_update_manifest_json' => $raw,
                    'signed_update_manifest_cached_at' => (string)time(),
                    'signed_update_manifest_error' => '',
                ]);
                return ['success' => true, 'payload' => $verified, 'from_cache' => false, 'stale' => false];
            }
            $error = 'update_manifest_verification_failed';
        } else {
            $error = 'update_gateway_unavailable';
        }

        $settings->set('signed_update_manifest_error', $error);
        if (!$forceRefresh && $cached !== null && $age <= self::STALE_FALLBACK_SECONDS) {
            return ['success' => true, 'payload' => $cached, 'from_cache' => true, 'stale' => true, 'warning' => $error];
        }

        return ['success' => false, 'error' => $error];
    }

    private function resolveEndpoint(?string $endpoint): string
    {
        if ($endpoint === null && defined('EASYCHAT_UPDATE_MANIFEST_ENDPOINT')) {
            $endpoint = (string)constant('EASYCHAT_UPDATE_MANIFEST_ENDPOINT');
        }

         
         
        foreach ([self::PRODUCTION_ENDPOINT, self::STAGE_ENDPOINT] as $trusted) {
            if (is_string($endpoint) && hash_equals($trusted, trim($endpoint))) {
                return $trusted;
            }
        }

        return self::PRODUCTION_ENDPOINT;
    }

     
    private function decodeAndVerify(string $raw): ?array
    {
        if ($raw === '' || strlen($raw) > 1024 * 1024) {
            return null;
        }
        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return null;
        }
        try {
            return $this->verifier->verify($decoded);
        } catch (\Throwable $e) {
            return null;
        }
    }
}
