<?php

namespace GriffinForms\Includes\Ai\Transports;

use GriffinForms\Includes\Ai\Contracts\AiClientInterface;
use GriffinForms\Includes\Ai\Exceptions\AiBrokerError;
use GriffinForms\Includes\Ai\Exceptions\ButlerTimeoutException;

class GeminiRestTransport implements AiClientInterface
{
    private const ENDPOINT_TEMPLATE = 'https://generativelanguage.googleapis.com/v1beta/models/%s:generateContent?key=%s';

    protected $api_key;
    protected $model;
    protected $timeout;
    protected $max_tokens;

    public function __construct(string $api_key, string $model, int $timeout = 20, ?int $max_tokens = null)
    {
        $this->api_key    = $api_key;
        $this->model      = $model ?: 'gemini-2.0-flash';
        $this->timeout    = $timeout > 0 ? $timeout : 20;
        $this->max_tokens = ($max_tokens !== null && $max_tokens > 0) ? $max_tokens : null;
    }

    public function request(string $prompt, array $context = []): array
    {
        if (empty($this->api_key)) {
            throw new AiBrokerError('AI request aborted: Missing API key.', 401);
        }

        $system_context = $context['system'] ?? 'You are a helpful assistant.';

        $endpoint = sprintf(self::ENDPOINT_TEMPLATE, rawurlencode($this->model), rawurlencode($this->api_key));

        $body = [
            'contents'          => [
                ['role' => 'user', 'parts' => [['text' => $prompt]]],
            ],
            'systemInstruction' => [
                'parts' => [['text' => $system_context]],
            ],
        ];

        if ($this->max_tokens !== null) {
            $body['generationConfig'] = ['maxOutputTokens' => $this->max_tokens];
        }

        $args = [
            'headers' => ['Content-Type' => 'application/json'],
            'body'    => wp_json_encode($body),
            'timeout' => $this->timeout,
        ];

        $response = wp_remote_post($endpoint, $args);

        if (is_wp_error($response)) {
            if ($this->isTimeoutError($response)) {
                throw new ButlerTimeoutException('The AI provider timed out before returning a response.', 408);
            }
            throw new AiBrokerError('Network failure: ' . $response->get_error_message(), 500);
        }

        $code          = wp_remote_retrieve_response_code($response);
        $response_body = wp_remote_retrieve_body($response);

        if ($code !== 200) {
            throw new AiBrokerError('API integration error: HTTP ' . $code . ' (' . $response_body . ')', $code);
        }

        $decoded = json_decode($response_body, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new AiBrokerError('Invalid JSON response retrieved from AI service provider.', 500);
        }

        $candidates = $decoded['candidates'] ?? [];

        if (empty($candidates)) {
            throw new AiBrokerError('Gemini returned no candidates. The request may have been blocked.', 500);
        }

        $finish_reason = $candidates[0]['finishReason'] ?? '';
        if ($finish_reason === 'SAFETY') {
            throw new AiBrokerError('The request was blocked by Gemini safety filters. Please revise your input.', 400);
        }

        return [
            'success' => true,
            'content' => $candidates[0]['content']['parts'][0]['text'] ?? '',
            'raw'     => $decoded,
        ];
    }

    protected function isTimeoutError(\WP_Error $response): bool
    {
        $message = strtolower((string) $response->get_error_message());
        $code    = (string) $response->get_error_code();

        return str_contains($message, 'timed out')
            || str_contains($message, 'timeout')
            || str_contains($message, 'curl error 28')
            || $code === 'http_request_timeout';
    }
}
