<?php

declare(strict_types=1);

namespace Huilvtong;

use RuntimeException;

final class HuilvtongClient
{
    public function __construct(
        private readonly string $baseUrl,
        private readonly string $apiKey,
        private readonly int $timeout = 15,
    ) {
        if (!str_starts_with($apiKey, 'hvt_live_')) {
            throw new RuntimeException('API key format is invalid.');
        }
    }

    public function rates(string $base = 'USD', array $symbols = []): array
    {
        return $this->get('rates', ['base' => $base, 'symbols' => implode(',', $symbols)]);
    }

    public function convert(float $amount, string $from = 'USD', string $to = 'CNY'): array
    {
        return $this->get('convert', compact('amount', 'from', 'to'));
    }

    public function currencies(int $limit = 50, ?string $cursor = null, string $query = ''): array
    {
        return $this->get('currencies', ['limit' => $limit, 'cursor' => $cursor, 'q' => $query]);
    }

    public function history(string $from, string $to, array $options = []): array
    {
        return $this->get('history', ['from' => $from, 'to' => $to] + $options);
    }

    public function datasets(array $options = []): array
    {
        return $this->get('datasets', $options);
    }

    public function get(string $endpoint, array $query = [], array $headers = []): array
    {
        if (!function_exists('curl_init')) {
            throw new RuntimeException('The cURL extension is required.');
        }
        $query = array_filter($query, static fn (mixed $value): bool => $value !== null && $value !== '');
        $url = rtrim($this->baseUrl, '/') . '/api/v2/' . rawurlencode($endpoint);
        if ($query !== []) {
            $url .= '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986);
        }
        $handle = curl_init($url);
        curl_setopt_array($handle, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => array_merge(['Accept: application/json', 'X-API-Key: ' . $this->apiKey], $headers),
            CURLOPT_CONNECTTIMEOUT => min(5, $this->timeout), CURLOPT_TIMEOUT => $this->timeout,
            CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2,
        ]);
        $body = curl_exec($handle);
        $status = (int) curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
        $error = curl_error($handle);
        curl_close($handle);
        if (!is_string($body)) {
            throw new RuntimeException('Network error: ' . ($error ?: 'unknown'));
        }
        $decoded = json_decode($body, true);
        if (!is_array($decoded)) {
            throw new RuntimeException('The API returned invalid JSON (HTTP ' . $status . ').');
        }
        if ($status < 200 || $status >= 300 || ($decoded['ok'] ?? false) !== true) {
            throw new RuntimeException((string) ($decoded['error']['message'] ?? ('API request failed with HTTP ' . $status)));
        }
        return $decoded;
    }
}
