<?php

namespace Modules\ProductCompat\Entities\Enrichment\Providers;

use App\Product;
use Illuminate\Support\Facades\Http;
use Modules\ProductCompat\Entities\Enrichment\EnrichmentProvider;
use Modules\ProductCompat\Entities\Enrichment\EnrichmentResult;
use Modules\ProductCompat\Entities\Services\CustomFieldParser;
use Modules\ProductCompat\Entities\Services\Settings;

/**
 * FREE alternative to the paid SerpApi: Google Programmable Search (Custom
 * Search JSON API) — 100 queries/day free. Searches by brand + product name and
 * mines part-number-like tokens from result titles/snippets. Works for the
 * part-numberless products Icecat can't match. Needs a free API key + a search
 * engine id (cx), set from module Settings.
 */
class GoogleCseProvider implements EnrichmentProvider
{
    protected CustomFieldParser $parser;

    public function __construct(?CustomFieldParser $parser = null)
    {
        $this->parser = $parser ?? new CustomFieldParser();
    }

    public function key(): string
    {
        return 'google';
    }

    public function isAvailable(): bool
    {
        return ! empty(Settings::get('google_cse_key', env('PRODUCTCOMPAT_GOOGLE_KEY')))
            && ! empty(Settings::get('google_cse_cx', env('PRODUCTCOMPAT_GOOGLE_CX')));
    }

    public function fetch(Product $product): EnrichmentResult
    {
        $key = Settings::get('google_cse_key', env('PRODUCTCOMPAT_GOOGLE_KEY'));
        $cx  = Settings::get('google_cse_cx', env('PRODUCTCOMPAT_GOOGLE_CX'));
        $timeout = (int) config('productcompat.enrichment.timeout', 15);
        $conf = (int) (config('productcompat.enrichment.confidence.google') ?? 50);

        $brand = trim((string) optional($product->brand)->name);
        $query = trim($brand . ' ' . $product->name . ' part number');
        if ($query === 'part number') {
            return EnrichmentResult::empty(['reason' => 'no brand/name to search']);
        }

        try {
            $resp = Http::timeout($timeout)->get('https://www.googleapis.com/customsearch/v1', [
                'key' => $key, 'cx' => $cx, 'q' => $query, 'num' => 10,
            ]);
        } catch (\Throwable $e) {
            return EnrichmentResult::fail($e->getMessage());
        }

        if ($resp->status() === 429) {
            Settings::set('google_limit_reached_at', now()->toDateTimeString());
            return EnrichmentResult::fail('google_limit: daily quota reached (HTTP 429)');
        }
        if ($resp->failed()) {
            return EnrichmentResult::fail('Google CSE HTTP ' . $resp->status(), $resp->body());
        }

        $json = $resp->json() ?? [];
        $texts = [];
        foreach ((array) ($json['items'] ?? []) as $it) {
            $texts[] = ($it['title'] ?? '') . ' ' . ($it['snippet'] ?? '');
        }

        $parts = array_map(function ($p) use ($conf) {
            return ['value' => $p['value'], 'type' => $p['type'], 'confidence' => min(95, $conf + max(0, $p['hits'] - 1) * 12)];
        }, $this->parser->extractCorroborated($texts, 1, 5));

        return new EnrichmentResult(true, ['part_numbers' => $parts], [
            'query'   => $query,
            'results' => count((array) ($json['items'] ?? [])),
            'matched' => count($parts),
        ]);
    }
}
