<?php

namespace classes;

use Exception;
use interfaces\weatherapi_i;
use weatherapi\weatherapi_c;

require_once WD . '/modules/weatherapi/weatherapi_c.php';

class weatherapi implements weatherapi_i
{
    public weatherapi_c $config;

    private string $api_url = 'https://api.weatherapi.com/v1/';

    public function __construct()
    {
        $this->config = new weatherapi_c();
    }

    public function requireModuleEnabled(): void
    {
        if (!$this->config->enabled->isTrue()) {
            throw new Exception('The weatherapi module is not enabled');
        }
    }

    public function requireValidSecretKey(): void
    {
        if ($this->config->secret_key->getVariableValue() === null || $this->config->secret_key->getVariableValue() === '') {
            throw new Exception('Invalid secret key defined in the config (weatherapi_secret_key_c)');
        }
    }

    public function sendRequest(string $endpoint, array $query = []): object
    {
        $this->requireModuleEnabled();
        $this->requireValidSecretKey();

        $endpoint = ltrim($endpoint, '/');
        $query = array_merge(['key' => $this->config->secret_key->getVariableValue()], $query);
        $url = $this->api_url . $endpoint . '?' . http_build_query($query);

        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'GET',
        ]);

        $response = curl_exec($curl);
        $status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        $error = curl_error($curl);
        curl_close($curl);

        if ($error) {
            throw new Exception('cURL request failed: ' . $error);
        }

        if ($response === false || $response === '') {
            throw new Exception('Empty response from WeatherAPI');
        }

        $decoded = json_decode($response);
        if (json_last_error() !== JSON_ERROR_NONE || !is_object($decoded) && !is_array($decoded)) {
            throw new Exception('Invalid response from WeatherAPI');
        }

        if ($status_code >= 400) {
            $message = 'WeatherAPI request failed with HTTP ' . $status_code;
            if (is_object($decoded) && isset($decoded->error->message)) {
                $message .= ': ' . $decoded->error->message;
            }
            throw new Exception($message);
        }

        return (object)$decoded;
    }

    public function current(string $query, array $options = []): object
    {
        return $this->sendRequest('current.json', array_merge(['q' => $query], $options));
    }

    public function forecast(string $query, int $days = 1, array $options = []): object
    {
        return $this->sendRequest('forecast.json', array_merge(['q' => $query, 'days' => $days], $options));
    }

    public function history(string $query, string $date, array $options = []): object
    {
        return $this->sendRequest('history.json', array_merge(['q' => $query, 'dt' => $date], $options));
    }

    public function astronomy(string $query, string $date, array $options = []): object
    {
        return $this->sendRequest('astronomy.json', array_merge(['q' => $query, 'dt' => $date], $options));
    }

    public function timezone(string $query, array $options = []): object
    {
        return $this->sendRequest('timezone.json', array_merge(['q' => $query], $options));
    }

    public function sports(string $query, array $options = []): object
    {
        return $this->sendRequest('sports.json', array_merge(['q' => $query], $options));
    }

    public function search(string $query, array $options = []): object
    {
        return $this->sendRequest('search.json', array_merge(['q' => $query], $options));
    }

    public function marine(string $query, int $days = 1, array $options = []): object
    {
        return $this->sendRequest('marine.json', array_merge(['q' => $query, 'days' => $days], $options));
    }

    public function future(string $query, string $date, array $options = []): object
    {
        return $this->sendRequest('future.json', array_merge(['q' => $query, 'dt' => $date], $options));
    }
}
