<?php

namespace Modules\WhatsApp\Entities\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Modules\WhatsApp\Entities\WaMessage;

/**
 * Reads a customer-sent product photo with a multimodal model and extracts the
 * identifiers we need to search the catalogue (brand, model, part/SKU number,
 * capacity, visible text). Uses the business's own AiProvider credentials, so
 * no extra config. Returns a short comma-separated string, or '' if nothing
 * useful / the provider isn't vision-capable. Never throws.
 */
class WaVisionExtractor
{
    private const PROMPT =
        "A customer sent this photo of a product (e.g. a battery, charger, cartridge or device) to a shop. "
        . "Extract identifiers that help find this exact product in a catalogue: brand, model name, "
        . "part/model/SKU number (codes like 'PT434', 'A1322', 'CN045'), capacity/voltage/size, and any other clearly visible codes or text. "
        . "Reply with ONLY a short comma-separated list of the key identifiers (no sentences). If nothing is readable, reply exactly: NONE.";

    /** Extract from a stored inbound image message. */
    public function extractFromMessage($settings, WaMessage $message): string
    {
        $payload = $message->payload ?? [];
        $path = $payload['media_path'] ?? null;
        $mime = $payload['mime'] ?? 'image/jpeg';
        if (!$path) {
            return '';
        }

        try {
            $bytes = Storage::exists($path) ? Storage::get($path) : null;
            if ($bytes === null && is_file($path)) {
                $bytes = file_get_contents($path);
            }
        } catch (\Throwable $e) {
            return '';
        }
        if (empty($bytes)) {
            return '';
        }

        return $this->extract($settings, $bytes, $mime);
    }

    public function extract($settings, string $imageBytes, string $mime = 'image/jpeg'): string
    {
        try {
            $b64 = base64_encode($imageBytes);
            switch ($settings->provider) {
                case 'gemini':
                    return $this->gemini($settings, $b64, $mime);
                case 'openai':
                case 'openai_compatible':
                    return $this->openai($settings, $b64, $mime);
                default:
                    return '';
            }
        } catch (\Throwable $e) {
            Log::warning('WaVisionExtractor error: ' . $e->getMessage());
            return '';
        }
    }

    private function gemini($s, string $b64, string $mime): string
    {
        $url = 'https://generativelanguage.googleapis.com/v1beta/models/'
            . rawurlencode((string) $s->model) . ':generateContent?key=' . urlencode((string) $s->api_key);

        $resp = Http::timeout(60)->post($url, [
            'contents' => [[
                'role'  => 'user',
                'parts' => [
                    ['inline_data' => ['mime_type' => $mime, 'data' => $b64]],
                    ['text' => self::PROMPT],
                ],
            ]],
            'generationConfig' => ['temperature' => 0.1, 'maxOutputTokens' => 300, 'thinkingConfig' => ['thinkingBudget' => 0]],
        ]);

        if (!$resp->successful()) {
            return '';
        }
        $text = '';
        foreach (($resp->json('candidates.0.content.parts') ?? []) as $p) {
            $text .= $p['text'] ?? '';
        }
        return $this->clean($text);
    }

    private function openai($s, string $b64, string $mime): string
    {
        $base = $s->provider === 'openai' ? 'https://api.openai.com/v1' : rtrim((string) $s->base_url, '/');
        $resp = Http::withToken((string) $s->api_key)->timeout(60)->post($base . '/chat/completions', [
            'model'       => $s->model,
            'max_tokens'  => 300,
            'temperature' => 0.1,
            'messages'    => [[
                'role'    => 'user',
                'content' => [
                    ['type' => 'text', 'text' => self::PROMPT],
                    ['type' => 'image_url', 'image_url' => ['url' => "data:{$mime};base64,{$b64}"]],
                ],
            ]],
        ]);
        if (!$resp->successful()) {
            return '';
        }
        return $this->clean((string) $resp->json('choices.0.message.content'));
    }

    private function clean(string $text): string
    {
        $text = trim($text);
        return ($text === '' || strtoupper($text) === 'NONE') ? '' : $text;
    }
}
