<?php

namespace App\Libraries;

use Config\ApiFootball;
use RuntimeException;

class ApiFootballClient
{
    protected ApiFootball $config;
    protected ?string $lastRateLimitRemaining = null;

    public function __construct(?ApiFootball $config = null)
    {
        $this->config = $config ?? config('ApiFootball');
    }

    public function get(string $endpoint, array $query = []): array
    {
        $apiKey = $this->config->getApiKey();
        if ($apiKey === '') {
            throw new RuntimeException('API_FOOTBALL_KEY is not configured.');
        }

        $url = rtrim($this->config->baseUrl, '/') . '/' . ltrim($endpoint, '/');
        if ($query !== []) {
            $url .= '?' . http_build_query($query);
        }

        $client = \Config\Services::curlrequest([
            'timeout' => 30,
            'http_errors' => false,
        ]);

        $response = $client->get($url, [
            'headers' => [
                'x-apisports-key' => $apiKey,
                'Accept' => 'application/json',
            ],
        ]);

        $this->lastRateLimitRemaining = $response->getHeaderLine('x-ratelimit-requests-remaining') ?: null;

        $status = $response->getStatusCode();
        $body = json_decode($response->getBody(), true);

        if (!is_array($body)) {
            throw new RuntimeException('Invalid JSON from API-Football.');
        }

        if ($status >= 400) {
            $message = $body['message'] ?? ('HTTP ' . $status);
            throw new RuntimeException('API-Football error: ' . $message);
        }

        if (!empty($body['errors'])) {
            $errors = is_array($body['errors']) ? json_encode($body['errors']) : (string) $body['errors'];
            throw new RuntimeException('API-Football errors: ' . $errors);
        }

        return $body;
    }

    public function getResponseItems(string $endpoint, array $query = []): array
    {
        $body = $this->get($endpoint, $query);

        return $body['response'] ?? [];
    }

    /**
     * Fetch all pages when an endpoint supports pagination (/players, /fixtures, etc.).
     * Reference endpoints like /leagues and /countries return everything in one response
     * and reject the page parameter — those use getResponseItems() instead.
     *
     * @return array{items: list<array>, pages: int, rate_limit_remaining: ?string}
     */
    public function getAllResponseItems(string $endpoint, array $query = []): array
    {
        $endpoint = trim($endpoint, '/');

        // These endpoints do not accept ?page= (API returns "The Page field do not exist.").
        $singleShotEndpoints = ['leagues', 'countries', 'timezone', 'leagues/seasons', 'teams/seasons', 'teams/countries'];
        if (in_array($endpoint, $singleShotEndpoints, true)) {
            $items = $this->getResponseItems($endpoint, $query);

            return [
                'items' => $items,
                'pages' => 1,
                'rate_limit_remaining' => $this->lastRateLimitRemaining,
            ];
        }

        $all = [];
        $body = $this->get($endpoint, $query);
        $items = $body['response'] ?? [];
        if (is_array($items)) {
            $all = array_merge($all, $items);
        }

        $totalPages = max(1, (int) ($body['paging']['total'] ?? 1));

        for ($page = 2; $page <= $totalPages; $page++) {
            $this->throttle();
            $body = $this->get($endpoint, array_merge($query, ['page' => $page]));
            $items = $body['response'] ?? [];
            if (is_array($items)) {
                $all = array_merge($all, $items);
            }
        }

        return [
            'items' => $all,
            'pages' => $totalPages,
            'rate_limit_remaining' => $this->lastRateLimitRemaining,
        ];
    }

    public function throttle(): void
    {
        if ($this->config->requestDelayMs > 0) {
            usleep($this->config->requestDelayMs * 1000);
        }
    }

    public function getLastRateLimitRemaining(): ?string
    {
        return $this->lastRateLimitRemaining;
    }
}
