<?php

namespace App\Services;

use App\Enums\UserTypeEnum;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;

class GeminiService
{
    private const API_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/models';

    private Client $client;

    public function __construct()
    {
        $this->client = new Client(['timeout' => 30]);
    }

    public function sendMessage(string $message, UserTypeEnum $userType, array $history = []): string
    {
        $apiKey = config('services.gemini.api_key');
        $model  = config('services.gemini.model');

        $contents = $this->buildContents($history, $message);

        $payload = [
            'systemInstruction' => [
                'parts' => [['text' => $this->loadContext($userType)]],
            ],

            'contents' => $contents,

            'generationConfig' => [
                'temperature'     => 0.4,
                'maxOutputTokens' => 2048,
                'thinkingConfig'  => ['thinkingBudget' => 0],
            ],
        ];

        try {
            $response = $this->client->post($this->buildApiUrl($model), [
                'json'  => $payload,
                'query' => ['key' => $apiKey],
            ]);

            $data = json_decode($response->getBody()->getContents(), true);

            $this->logTruncatedResponse($data, $model);

            return data_get($data, 'candidates.0.content.parts.0.text', __('chatbot.error_response'));
        } catch (GuzzleException $e) {
            $this->logGeminiError($e, $model);

            return __('chatbot.error_response');
        }
    }

    //

    private function buildApiUrl(string $model): string
    {
        return self::API_BASE_URL . '/' . rawurlencode($model) . ':generateContent';
    }

    private function buildContents(array $history, string $newMessage): array
    {
        $contents = [];

        foreach ($history as $entry) {
            $role = data_get($entry, 'role') === 'model' ? 'model' : 'user';

            $contents[] = [
                'role'  => $role,
                'parts' => [['text' => data_get($entry, 'text')]],
            ];
        }

        $contents[] = [
            'role'  => 'user',
            'parts' => [['text' => $newMessage]],
        ];

        return $contents;
    }

    private function loadContext(UserTypeEnum $userType): string
    {
        $restrictionsFile = resource_path('chatbot/restricoes.md');
        $restrictions     = file_exists($restrictionsFile) ? file_get_contents($restrictionsFile) : '';

        $contextFile = match ($userType) {
            UserTypeEnum::CLIENT   => resource_path('chatbot/context_cliente.txt'),
            UserTypeEnum::PROVIDER => resource_path('chatbot/context_prestador.txt'),
            default                => resource_path('chatbot/context_cliente.txt'),
        };

        $context = file_exists($contextFile) ? file_get_contents($contextFile) : '';

        return $restrictions . "\n\n" . $context;
    }

    private function logTruncatedResponse(?array $data, string $model): void
    {
        if (data_get($data, 'candidates.0.finishReason') !== 'MAX_TOKENS') {
            return;
        }

        Log::warning('Resposta do Gemini truncada por limite de tokens', [
            'model'         => $model,
            'usageMetadata' => data_get($data, 'usageMetadata'),
        ]);
    }

    private function logGeminiError(GuzzleException $e, string $model): void
    {
        $context = [
            'model'   => $model,
            'message' => $this->sanitizeApiKey($e->getMessage()),
        ];

        if ($e instanceof RequestException && $e->hasResponse()) {
            $response = $e->getResponse();

            $context['status'] = $response->getStatusCode();
            $context['body']   = $this->sanitizeApiKey((string) $response->getBody());
        }

        Log::error('Erro na API do Gemini', $context);
    }

    private function sanitizeApiKey(string $message): string
    {
        return preg_replace('/([?&]key=)[^&\s"]+/i', '$1[REDACTED]', $message);
    }
}
