#!/usr/bin/env php
<?php
declare(strict_types=1);

/**
 * gsearch — vyhledávání na Googlu přes SerpApi
 *
 * Použití:
 *   gsearch "dotaz"               # 10 výsledků, čitelný výstup
 *   gsearch -n 5 "dotaz"          # 5 výsledků
 *   gsearch --json "dotaz"        # surový JSON (pro další zpracování)
 *   gsearch --usage               # kolik dotazů jsem tento měsíc spotřeboval
 *   gsearch --hl cs --gl cz "…"   # jazyk/region (default en/us)
 *
 * Klíč:  .config/serpapi.key   (nebo proměnná prostředí SERPAPI_KEY)
 *
 * Free tier SerpApi je 250 dotazů/měsíc a obnovuje se. Skript si spotřebu
 * počítá sám a po dosažení stropu odmítne volat API — aby se nikdy
 * nezačalo platit. Opakované dotazy se 7 dní cachují (nezdráží kvótu).
 */

$ROOT     = dirname(__DIR__);
$CONF     = $ROOT . '/.config';
$KEYFILE  = $CONF . '/serpapi.key';
$USAGEF   = $CONF . '/gsearch-usage.json';
$CACHEDIR = $CONF . '/gsearch-cache';
$MAXMONTH = 250;          // free tier SerpApi
$CACHETTL = 7 * 86400;    // 7 dní
$ENDPOINT = 'https://serpapi.com/search.json';

// ---------------------------------------------------------------- argumenty

$args = $argv;
array_shift($args);

$num = 10; $json = false; $noCache = false; $showUsage = false;
$hl = 'en'; $gl = 'us';
$parts = [];

while ($args) {
    $a = array_shift($args);
    switch ($a) {
        case '-n': case '--num':  $num = max(1, min(100, (int) array_shift($args))); break;
        case '--json':            $json = true; break;
        case '--no-cache':        $noCache = true; break;
        case '--usage':           $showUsage = true; break;
        case '--hl':              $hl = (string) array_shift($args); break;
        case '--gl':              $gl = (string) array_shift($args); break;
        case '-h': case '--help': help(); exit(0);
        default:                  $parts[] = $a;
    }
}

$query = trim(implode(' ', $parts));

if (!$showUsage && $query === '') {
    fwrite(STDERR, "chyba: chybí dotaz\n\n");
    help();
    exit(2);
}

// ------------------------------------------------------------------ kvóta

$month = date('Y-m');
$usage = read_usage($USAGEF);
$used  = (int) ($usage[$month] ?? 0);

// --usage nepotřebuje klíč
if ($showUsage) {
    printf("SerpApi — %s\n", $month);
    printf("spotřebováno: %d / %d\n", $used, $MAXMONTH);
    printf("zbývá:        %d\n", max(0, $MAXMONTH - $used));
    exit(0);
}

// ------------------------------------------------------------------- klíč

$key = getenv('SERPAPI_KEY') ?: '';
if ($key === '' && is_readable($KEYFILE)) {
    $key = trim((string) file_get_contents($KEYFILE));
}
if ($key === '') {
    fwrite(STDERR, "chyba: chybí API klíč.\n");
    fwrite(STDERR, "Ulož ho do $KEYFILE  (chmod 600), nebo nastav SERPAPI_KEY.\n");
    exit(3);
}

if ($used >= $MAXMONTH) {
    fwrite(STDERR, sprintf(
        "chyba: měsíční limit vyčerpán (%d/%d dotazů za %s).\n" .
        "Free tier se obnoví 1. dne dalšího měsíce.\n",
        $used, $MAXMONTH, $month
    ));
    exit(4);
}

// ------------------------------------------------------------------ cache

$cacheKey  = md5(json_encode([$query, $num, $hl, $gl]));
$cacheFile = $CACHEDIR . '/' . $cacheKey . '.json';

if (!$noCache && is_readable($cacheFile) && (time() - filemtime($cacheFile)) < $CACHETTL) {
    $data = json_decode((string) file_get_contents($cacheFile), true);
    if (is_array($data)) {
        output($data, $json, true);
        exit(0);
    }
}

// ------------------------------------------------------------------- volání

$url = $ENDPOINT . '?' . http_build_query([
    'engine'  => 'google',
    'q'       => $query,
    'num'     => $num,
    'hl'      => $hl,
    'gl'      => $gl,
    'api_key' => $key,
]);

$ctx = stream_context_create([
    'http' => [
        'timeout'       => 20,
        'ignore_errors' => true,
        'header'        => "Accept: application/json\r\n",
    ],
]);

$raw = @file_get_contents($url, false, $ctx);
if ($raw === false) {
    fwrite(STDERR, "chyba: nepodařilo se spojit se serpapi.com\n");
    exit(5);
}

$data = json_decode($raw, true);
if (!is_array($data)) {
    fwrite(STDERR, "chyba: odpověď není JSON\n");
    exit(5);
}

if (isset($data['error'])) {
    $msg = (string) $data['error'];
    fwrite(STDERR, "chyba API: $msg\n");
    // U chyby kvóty na straně SerpApi si lokální počítadlo dorovnáme na strop.
    if (stripos($msg, 'run out of searches') !== false || stripos($msg, 'plan') !== false) {
        $usage[$month] = $MAXMONTH;
        write_usage($USAGEF, $usage);
    }
    exit(6);
}

// ------------------------------------------------------------------ zápis

$usage[$month] = $used + 1;
write_usage($USAGEF, $usage);

if (!is_dir($CACHEDIR)) {
    @mkdir($CACHEDIR, 0700, true);
}
@file_put_contents($cacheFile, $raw);

output($data, $json, false);

// ---------------------------------------------------------------- funkce

function output(array $data, bool $json, bool $fromCache): void
{
    if ($json) {
        echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), "\n";
        return;
    }

    if ($fromCache) {
        fwrite(STDERR, "[cache] ");
    }

    // Rychlá odpověď / znalostní panel — často to nejcennější
    $box = $data['answer_box'] ?? null;
    if (is_array($box)) {
        $txt = $box['answer'] ?? $box['snippet'] ?? $box['result'] ?? null;
        if (is_string($txt) && $txt !== '') {
            echo "ODPOVĚĎ: ", trim(preg_replace('/\s+/', ' ', $txt)), "\n\n";
        }
    }

    $kg = $data['knowledge_graph'] ?? null;
    if (is_array($kg) && !empty($kg['description'])) {
        echo "PANEL: ", trim((string) $kg['description']), "\n\n";
    }

    $results = $data['organic_results'] ?? [];
    if (!is_array($results) || !$results) {
        fwrite(STDERR, "žádné organické výsledky\n");
        return;
    }

    $i = 0;
    foreach ($results as $r) {
        if (!is_array($r)) {
            continue;
        }
        $i++;
        $title = trim((string) ($r['title'] ?? ''));
        $link  = trim((string) ($r['link'] ?? ''));
        $snip  = trim(preg_replace('/\s+/', ' ', (string) ($r['snippet'] ?? '')));
        $date  = trim((string) ($r['date'] ?? ''));

        printf("%d. %s\n", $i, $title);
        printf("   %s\n", $link);
        if ($date !== '') {
            printf("   [%s]\n", $date);
        }
        if ($snip !== '') {
            printf("   %s\n", $snip);
        }
        echo "\n";
    }
}

function read_usage(string $file): array
{
    if (!is_readable($file)) {
        return [];
    }
    $d = json_decode((string) file_get_contents($file), true);
    return is_array($d) ? $d : [];
}

function write_usage(string $file, array $usage): void
{
    $dir = dirname($file);
    if (!is_dir($dir)) {
        @mkdir($dir, 0700, true);
    }
    // Ponecháme jen posledních 12 měsíců, ať soubor neroste
    krsort($usage);
    $usage = array_slice($usage, 0, 12, true);
    @file_put_contents($file, json_encode($usage, JSON_PRETTY_PRINT));
}

function help(): void
{
    echo <<<TXT
    gsearch — vyhledávání na Googlu přes SerpApi

      gsearch "dotaz"              10 výsledků
      gsearch -n 5 "dotaz"         5 výsledků
      gsearch --json "dotaz"       surový JSON
      gsearch --no-cache "dotaz"   obejít cache
      gsearch --usage              stav kvóty
      gsearch --hl cs --gl cz "…"  jazyk / region

    Klíč: .config/serpapi.key nebo \$SERPAPI_KEY

    TXT;
}
