🌹🏠🌹？》《》？《》？<?php

namespace App\Services;

use Illuminate\Http\Client\Response;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Http;

class GroqImagenService
{
    private const MODELO = 'qwen/qwen3.8-27b';

    private const ENDPOINT = 'https://api.groq.com/openai/v1/chat/completions';

    private const PROMPT = <<<'PROMPT'
Analiza la imagen adjunta para determinar si funciona como un comprobante de entrega o documento logístico válido (Remitos tipo A, R, P, facturas o recibos). Debe ser un documento impreso o digital que contenga información legible como membretes, tablas de artículos, o identificadores de tipo (A, R, P). Se considera válido si presenta firmas manuscritas, sellos de recepción, o aclaraciones de nombre/DNI. Rechaza terminantemente imágenes que contengan personas (caras), objetos irrelevantes que no sean el documento, o cualquier contenido inapropiado/ofensivo. El documento debe ser lo suficientemente claro para distinguir que es papelería comercial.

Responde ÚNICAMENTE con un JSON con este formato:
{
  "es_valida": <boolean>,
  "tipo_documento": "<Remito R, P, A, Factura, Firma sola o 'Desconocido'>",
  "descripcion": "<breve descripción de los elementos detectados: ej. firma y sello sobre remito R>",
  "motivo_rechazo": "<especificar si es una persona, imagen borrosa, objeto ajeno o falta de datos; cadena vacía si es válida>"
}
PROMPT;

    /**
     * Envía la imagen a la API de Groq y devuelve el análisis.
     *
     * @return array{es_valida?: bool, descripcion?: string, motivo_rechazo?: string, error?: string}
     */
    public function analizar(UploadedFile $archivo): array
    {
        $apiKey = config('services.groq.api_key');
        $apiKeySecundaria = config('services.groq.secondary_api_key');

        if (empty($apiKey)) {
            return ['error' => 'API key de Groq no configurada.'];
        }

        $contenido = file_get_contents($archivo->getRealPath());
        if ($contenido === false) {
            return ['error' => 'No se pudo leer el archivo para enviarlo a Groq.'];
        }

        $imagenBase64 = base64_encode($contenido);
        $mimeType     = $archivo->getMimeType() ?? 'image/jpeg';
        $dataUrl      = "data:{$mimeType};base64,{$imagenBase64}";

        $response = $this->consultarGroq($apiKey, $dataUrl);

        if ($response->status() === 429 && !empty($apiKeySecundaria) && $apiKeySecundaria !== $apiKey) {
            $response = $this->consultarGroq($apiKeySecundaria, $dataUrl);
        }

        if (!$response->successful()) {
            return ['error' => 'Error al conectar con Groq (HTTP ' . $response->status() . ').'];
        }

        $data  = $response->json();
        $texto = $data['choices'][0]['message']['content'] ?? null;

        if ($texto === null || trim($texto) === '') {
            return ['error' => 'Respuesta inesperada de Groq: no se encontró texto.'];
        }

        $resultado = $this->parsearJsonRespuesta($texto);

        if ($resultado === null) {
            return ['error' => 'No se pudo interpretar la respuesta JSON de Groq.'];
        }

        return $resultado;
    }

    private function consultarGroq(string $apiKey, string $dataUrl): Response
    {
        return Http::withHeaders([
                'Authorization' => 'Bearer ' . $apiKey,
                'Content-Type'  => 'application/json',
            ])
            ->timeout(45)
            ->post(self::ENDPOINT, [
                'model'                 => self::MODELO,
                'temperature'           => 0.2,
                'max_completion_tokens' => 1024,
                'top_p'                 => 1,
                'stream'                => false,
                // Qwen 3.8 piensa por defecto y se come el budget de tokens;
                // instruct mode (none) + JSON mode para una respuesta parseable.
                'reasoning_effort'      => 'none',
                'reasoning_format'      => 'hidden',
                'response_format'       => ['type' => 'json_object'],
                'messages'              => [
                    [
                        'role'    => 'user',
                        'content' => [
                            [
                                'type'      => 'image_url',
                                'image_url' => ['url' => $dataUrl],
                            ],
                            [
                                'type' => 'text',
                                'text' => self::PROMPT,
                            ],
                        ],
                    ],
                ],
            ]);
    }

    /**
     * Extrae un objeto JSON usable aunque venga con markdown o restos de thinking.
     *
     * @return array<string, mixed>|null
     */
    private function parsearJsonRespuesta(string $texto): ?array
    {
        $texto = preg_replace('/<think>.*?<\/think>/is', '', $texto) ?? $texto;
        $texto = trim($texto);

        $candidatos = [$texto];

        if (preg_match('/```(?:json)?\s*(\{.*?\})\s*```/is', $texto, $m)) {
            $candidatos[] = $m[1];
        }

        if (preg_match('/\{(?:[^{}]|(?R))*\}/s', $texto, $m)) {
            $candidatos[] = $m[0];
        } elseif (preg_match('/\{.*\}/s', $texto, $m)) {
            $candidatos[] = $m[0];
        }

        foreach ($candidatos as $candidato) {
            $resultado = json_decode(trim($candidato), true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($resultado)) {
                return $resultado;
            }
        }

        return null;
    }
}
