<?php
/**
 * Webhook alıcısı (PHP 8.1+): "dürt ve çek" deseni. Bir web sunucusunun arkasında tek dosya olarak çalışır.
 *
 * İmzayı (Standard Webhooks) ve zaman damgasını (±5 dk) doğrular, webhook-id'yi 24 saat saklar, hemen 202 döner ve
 * içeriği akıştan çeker (../baglayici). Alıcı denetiminin dört isteğini geçer: doğru imza 202, bozuk imza 401,
 * eski zaman damgası 401, aynı webhook-id 200.
 *
 * Ortam: YHA_WEBHOOK_SIRRI=whsec_...[,whsec_eski], YHA_WEBHOOK_KAYIT (webhook-id deposu, varsayılan webhook-kayit.json),
 *        YHA_ANAHTAR (doluysa dürtüde bağlayıcı çalışır).
 * Deneme: php -S 127.0.0.1:8080 webhook-alici.php
 */

declare(strict_types=1);

namespace YhaOrnek;

const TOLERANS = 300;
const SAKLAMA = 86400;

/** @param string[] $sirlar  @param array<string,string> $basliklar (küçük harf anahtarlar) */
function imzaGecerli(array $sirlar, array $basliklar, string $govde, ?int $simdi = null): bool
{
    $wid = $basliklar['webhook-id'] ?? '';
    $zaman = $basliklar['webhook-timestamp'] ?? '';
    $imzalar = $basliklar['webhook-signature'] ?? '';
    if ($wid === '' || !ctype_digit($zaman) || $imzalar === '') {
        return false;
    }
    if (abs(($simdi ?? time()) - (int) $zaman) > TOLERANS) {
        return false;
    }
    foreach ($sirlar as $sir) {
        $anahtar = base64_decode(preg_replace('/^whsec_/', '', $sir), true);
        $beklenen = base64_encode(hash_hmac('sha256', "{$wid}.{$zaman}.{$govde}", (string) $anahtar, true));
        foreach (explode(' ', $imzalar) as $p) {
            if (str_starts_with($p, 'v1,') && hash_equals($beklenen, substr($p, 3))) {
                return true;
            }
        }
    }
    return false;
}

/** webhook-id ilk kez mi geliyor? (24 saat saklanır; dosya kilidiyle süreçler arası güvenli) */
function ilkKez(string $kayitDosyasi, string $wid): bool
{
    $f = fopen($kayitDosyasi, 'c+');
    flock($f, LOCK_EX);
    $kayit = json_decode(stream_get_contents($f) ?: '{}', true) ?: [];
    $kayit = array_filter($kayit, fn ($z) => $z > time() - SAKLAMA);
    $ilk = !isset($kayit[$wid]);
    $kayit[$wid] = time();
    ftruncate($f, 0);
    rewind($f);
    fwrite($f, json_encode($kayit));
    flock($f, LOCK_UN);
    fclose($f);
    return $ilk;
}

/** @return array{0:int,1:array} */
function isle(array $sirlar, array $basliklar, string $govde, string $kayitDosyasi): array
{
    if (strlen($govde) > 65536) {
        return [413, ['hata' => 'govde_cok_buyuk']];
    }
    if (!imzaGecerli($sirlar, $basliklar, $govde)) {
        return [401, ['hata' => 'imza_gecersiz']]; // imzasız isteğe hiçbir iş yapılmaz
    }
    if (!ilkKez($kayitDosyasi, $basliklar['webhook-id'])) {
        return [200, ['tekrar' => true]]; // aynı bildirim: sessizce kabul
    }
    $g = json_decode($govde, true);
    if (!is_array($g)) {
        return [400, ['hata' => 'json']];
    }
    if (($g['olay_turu'] ?? '') === 'sinama.ping') {
        return [200, ['alici' => 'yha-ornek-webhook-alici', 'surum' => '1.0.0']];
    }
    return [202, ['alindi' => true, 'durt' => ($g['olay_turu'] ?? '') !== 'sinama.denetim' && empty($g['deneme'])]];
}

if (PHP_SAPI !== 'cli') {
    $basliklar = array_change_key_case(function_exists('getallheaders') ? getallheaders() : [], CASE_LOWER);
    $sirlar = array_filter(array_map('trim', explode(',', (string) getenv('YHA_WEBHOOK_SIRRI'))));
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        [$durum, $yanit] = [405, ['hata' => 'yontem']];
    } else {
        [$durum, $yanit] = isle($sirlar, $basliklar, (string) file_get_contents('php://input'), getenv('YHA_WEBHOOK_KAYIT') ?: __DIR__ . '/webhook-kayit.json');
    }
    $durt = $yanit['durt'] ?? false;
    unset($yanit['durt']);
    http_response_code($durum);
    header('Content-Type: application/json');
    echo json_encode($yanit);
    if ($durt && getenv('YHA_ANAHTAR')) {
        if (function_exists('fastcgi_finish_request')) {
            fastcgi_finish_request(); // yanıt gitti; akıştan çekme arkadan
        }
        require_once __DIR__ . '/../baglayici/baglayici.php';
        (new Baglayici(new Api(getenv('YHA_KOK') ?: 'https://deneme.<alan>', (string) getenv('YHA_ANAHTAR')), __DIR__ . '/baglayici.json', __DIR__ . '/medya'))->cek();
    }
}
