<?php
declare(strict_types=1);
require __DIR__ . '/lib/bootstrap.php';
require_method(['POST']);
rate_limit('stripe-webhook', 180, 60);

$payload = (string) file_get_contents('php://input');
$signature = (string) ($_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '');
$secret = (string) config('stripe.webhook_secret', '');

function verify_stripe_signature(string $payload, string $header, string $secret, int $tolerance = 300): bool
{
    if ($secret === '' || strpos($secret, 'CHANGE_ME') !== false) {
        return false;
    }
    $timestamp = 0;
    $signatures = [];
    foreach (explode(',', $header) as $part) {
        [$key, $value] = array_pad(explode('=', trim($part), 2), 2, '');
        if ($key === 't') {
            $timestamp = (int) $value;
        } elseif ($key === 'v1') {
            $signatures[] = $value;
        }
    }
    if ($timestamp <= 0 || abs(time() - $timestamp) > $tolerance || !$signatures) {
        return false;
    }
    $expected = hash_hmac('sha256', $timestamp . '.' . $payload, $secret);
    foreach ($signatures as $candidate) {
        if (hash_equals($expected, $candidate)) {
            return true;
        }
    }
    return false;
}

if (!verify_stripe_signature($payload, $signature, $secret)) {
    json_response(['ok' => false, 'error' => 'Invalid Stripe signature'], 400);
}
$event = json_decode($payload, true);
if (!is_array($event) || empty($event['id']) || empty($event['type'])) {
    json_response(['ok' => false, 'error' => 'Invalid webhook payload'], 400);
}

if ($event['type'] === 'checkout.session.completed') {
    $session = $event['data']['object'] ?? [];
    $mac = (string) ($session['client_reference_id'] ?? $session['metadata']['mac'] ?? '');
    $paymentStatus = (string) ($session['payment_status'] ?? '');
    $sessionId = (string) ($session['id'] ?? '');
    $expectedAmount = (int) config('stripe.amount_cents', 0);
    $expectedCurrency = strtolower((string) config('stripe.currency', 'usd'));
    if ($mac === '' || $sessionId === '' || $paymentStatus !== 'paid' || (int) ($session['amount_total'] ?? -1) !== $expectedAmount ||
        strtolower((string) ($session['currency'] ?? '')) !== $expectedCurrency) {
        json_response(['ok' => false, 'error' => 'Payment verification failed'], 400);
    }

    $device = find_device(normalize_mac($mac));
    if (!$device) {
        json_response(['ok' => false, 'error' => 'Unknown checkout device'], 400);
    }
    $metadataDeviceId = (int) ($session['metadata']['device_id'] ?? 0);
    if ($metadataDeviceId > 0 && $metadataDeviceId !== (int) $device['id']) {
        json_response(['ok' => false, 'error' => 'Checkout device mismatch'], 400);
    }
    $pdo = db();
    $processed = false;
    $pdo->beginTransaction();
    try {
        $stmt = $pdo->prepare(
            'INSERT IGNORE INTO payments (device_id, stripe_event_id, stripe_session_id, amount_total, currency, status, payload)
             VALUES (?, ?, ?, ?, ?, ?, ?)'
        );
        $stmt->execute([(int) $device['id'], $event['id'], $sessionId, (int) $session['amount_total'],
            $expectedCurrency, $paymentStatus, $payload]);
        if ($stmt->rowCount() === 1) {
            $processed = true;
            $paidDays = max(1, (int) config('app.paid_days', 30));
            $pdo->prepare(
                'UPDATE devices SET status = ?, stripe_customer_id = COALESCE(?, stripe_customer_id),
                 active_until = DATE_ADD(IF(active_until IS NULL OR active_until < NOW(), NOW(), active_until), INTERVAL ? DAY)
                 WHERE id = ?'
            )->execute(['active', $session['customer'] ?? null, $paidDays, (int) $device['id']]);
        }
        $pdo->commit();
    } catch (Throwable $error) {
        $pdo->rollBack();
        throw $error;
    }
    if ($processed) {
        audit_log('payment.completed', (int) $device['id'], ['event_id' => $event['id'], 'session_id' => $sessionId]);
    }
}
json_response(['ok' => true]);
