<?php
// push_notifications.php
// نوتیف شخصی و اعلان عمومی + هندل واقعی Web Push

declare(strict_types=1);

require_once __DIR__ . '/vendor/autoload.php';

use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;

/**
 * گرفتن یک اینستنس WebPush (singleton)
 * - اول از push_secrets.php (و .env) می‌خواند
 * - بعد اگر لازم بود از getenv() با نام‌های مختلف
 */
function diminet_get_webpush(): ?WebPush
{
    static $instance = null;

    if ($instance instanceof WebPush) {
        return $instance;
    }

    // 1) مقادیر اولیه از getenv
    $publicKey  = getenv('VAPID_PUBLIC_KEY')
        ?: getenv('VAPIDPUBLICKEY')
        ?: '';

    $privateKey = getenv('VAPID_PRIVATE_KEY')
        ?: getenv('VAPIDPRIVATEKEY')
        ?: '';

    $subject    = getenv('VAPID_SUBJECT')
        ?: getenv('VAPIDSUBJECT')
        ?: 'mailto:mojtaba1052@gmail.com';

    // 2) اگر push_secrets.php وجود داشت، روی این مقادیر override می‌کنیم
    $cfgFile = __DIR__ . '/push_secrets.php';
    if (is_file($cfgFile)) {
        $cfg = require $cfgFile;
        if (is_array($cfg)) {
            if (!empty($cfg['vapid_public_key'])) {
                $publicKey = $cfg['vapid_public_key'];
            }
            if (!empty($cfg['vapid_private_key'])) {
                $privateKey = $cfg['vapid_private_key'];
            }
            if (!empty($cfg['vapid_subject'])) {
                $subject = $cfg['vapid_subject'];
            }
        }
    }

    if ($publicKey === '' || $privateKey === '') {
        $logLine = sprintf(
            "[%s] WebPush init FAILED: missing VAPID keys (public/private)\n",
            date('Y-m-d H:i:s')
        );
        @file_put_contents(__DIR__ . '/push_debug.log', $logLine, FILE_APPEND);
        return null;
    }

    $instance = new WebPush([
        'VAPID' => [
            'subject'    => $subject,
            'publicKey'  => $publicKey,
            'privateKey' => $privateKey,
        ],
    ]);

    // بهینه‌سازی هدر VAPID
    $instance->setReuseVAPIDHeaders(true);

    return $instance;
}

/**
 * ارسال Web Push برای یک subscription
 *
 * @param array $subscription ['endpoint' => ..., 'p256dh_key' => ..., 'auth_key' => ...]
 * @param array $payload      ['title' => ..., 'body' => ..., 'url' => ..., 'type' => ..., 'id' => ...]
 */
function sendWebPush(array $subscription, array $payload): bool
{
    $endpoint = $subscription['endpoint'] ?? '';
    if ($endpoint === '') {
        return false;
    }

    $webPush = diminet_get_webpush();

    $logPrefix = sprintf(
        "[%s] SEND PUSH → endpoint=%s",
        date('Y-m-d H:i:s'),
        substr($endpoint, 0, 80) . '...'
    );

    if (!$webPush) {
        @file_put_contents(
            __DIR__ . '/push_debug.log',
            $logPrefix . " | SKIP: no WebPush instance\n",
            FILE_APPEND
        );
        return false;
    }

    $sub = Subscription::create([
        'endpoint'  => $endpoint,
        'publicKey' => $subscription['p256dh_key'] ?? null,
        'authToken' => $subscription['auth_key']   ?? null,
        // 'contentEncoding' => 'aesgcm', // در صورت نیاز
    ]);

    $jsonPayload = json_encode($payload, JSON_UNESCAPED_UNICODE);

    try {
        $report  = $webPush->sendOneNotification($sub, $jsonPayload);
        $status  = null;
        $success = false;

        if (is_object($report)) {
            if (method_exists($report, 'getResponse') && $report->getResponse()) {
                $status = $report->getResponse()->getStatusCode();
            }
            if (method_exists($report, 'isSuccess')) {
                $success = (bool) $report->isSuccess();
            }
        }

        $line = $logPrefix
            . " | status=" . ($status ?? '?')
            . " | success=" . ($success ? '1' : '0')
            . " | payload=" . $jsonPayload . "\n";

        @file_put_contents(__DIR__ . '/push_debug.log', $line, FILE_APPEND);

        return $success;
    } catch (\Throwable $e) {
        $line = $logPrefix . " | ERROR: " . $e->getMessage() . "\n";
        @file_put_contents(__DIR__ . '/push_debug.log', $line, FILE_APPEND);
        return false;
    }
}

/**
 * نوتیف شخصی برای یک کاربر + ثبت در notifications + ارسال Web Push
 *
 * - اگر از این تابع استفاده کنی، بعد از ارسال پوش، ستون pushed_at همان رکورد notification پر می‌شود
 * - برای نوتیف‌هایی که دستی در DB می‌زاری، کرون push_sync.php کار رو انجام می‌دهد
 */
function notifyUser(
    PDO $pdo,
    int $userId,
    string $title,
    string $body,
    ?string $url = null,
    string $type = 'system'
): void {
    if ($userId <= 0) {
        return;
    }

    // ۱) ثبت در جدول notifications
    $stmt = $pdo->prepare("
        INSERT INTO notifications (user_id, type, title, body, is_read, created_at)
        VALUES (:user_id, :type, :title, :body, 0, NOW())
    ");
    $stmt->execute([
        ':user_id' => $userId,
        ':type'    => $type,
        ':title'   => $title,
        ':body'    => $body,
    ]);

    $notifId = (int) $pdo->lastInsertId();

    // ۲) ساخت payload
    $payload = [
        'title' => $title,
        'body'  => $body,
        'url'   => $url ?? '/index.php?tab=panel',
        'type'  => $type,
        'id'    => $notifId,
        'icon'  => '/assets/logo192.png'
    ];

    // ۳) ارسال پوش به همهٔ subscriptionهای این کاربر
    $sent = diminet_push_to_user($pdo, $userId, $payload);

    // ۴) اگر واقعاً حداقل یک subscription موفق بود → pushed_at را روی همین notification ست کن
    if ($sent > 0 && $notifId > 0) {
        $u = $pdo->prepare("UPDATE notifications SET pushed_at = NOW() WHERE id = :id");
        $u->execute([':id' => $notifId]);
    }
}

/**
 * اعلان عمومی برای همه‌ی کاربران + ثبت در announcements + ارسال Web Push
 *
 * - visible_scope = 0 → همه
 * - visible_scope = 1 → فقط لاگین‌ها (برای WebPush هم همینو رعایت می‌کنیم)
 */
function broadcastAnnouncement(
    PDO $pdo,
    string $title,
    string $body,
    ?string $url = null,
    int $visibleScope = 0
): void {
    // ۱) ثبت در جدول announcements
    $stmt = $pdo->prepare("
        INSERT INTO announcements (title, body, visible_scope, is_active, created_at)
        VALUES (:title, :body, :scope, 1, NOW())
    ");
    $stmt->execute([
        ':title' => $title,
        ':body'  => $body,
        ':scope' => $visibleScope,
    ]);

    $annId = (int) $pdo->lastInsertId();

    // ۲) payload مشترک
    $payload = [
        'title' => $title,
        'body'  => $body,
        'url'   => $url ?? '/index.php',
        'type'  => 'announcement',
        'id'    => $annId,
         'icon'  => '/assets/logo192.png'
    ];

    // فقط لاگین‌ها یا همه؟
    $onlyLoggedIn = ($visibleScope === 1);

    $sent = diminet_push_broadcast($pdo, $payload, $onlyLoggedIn);

    // ۳) اگر چیزی فرستادیم → pushed_at را پر کن
    if ($sent > 0 && $annId > 0) {
        $u = $pdo->prepare("UPDATE announcements SET pushed_at = NOW() WHERE id = :id");
        $u->execute([':id' => $annId]);
    }
}

/**
 * ارسال push به تمام subscriptionهای یک کاربر بر اساس payload
 *
 * @return int تعداد subscriptionهایی که گزارش موفق داشتند
 */
function diminet_push_to_user(PDO $pdo, int $userId, array $payload): int
{
    if ($userId <= 0) {
        return 0;
    }

    $stmt = $pdo->prepare("
        SELECT endpoint, p256dh_key, auth_key
        FROM push_subscriptions
        WHERE user_id = :user_id
    ");
    $stmt->execute([':user_id' => $userId]);
    $subs = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if (!$subs) {
        return 0;
    }

    $successCount = 0;

    foreach ($subs as $sub) {
        $ok = sendWebPush($sub, $payload);
        if ($ok) {
            $successCount++;
        }
    }

    return $successCount;
}

/**
 * ارسال push به همه‌ی subscriptionها (یا فقط کسانی که user_id دارند)
 *
 * @param bool $onlyLoggedIn اگر true باشد فقط ردیف‌هایی که user_id NOT NULL دارند
 * @return int تعداد subscriptionهایی که گزارش موفق داشتند
 */
function diminet_push_broadcast(PDO $pdo, array $payload, bool $onlyLoggedIn = false): int
{
    $sql = "SELECT endpoint, p256dh_key, auth_key FROM push_subscriptions";
    if ($onlyLoggedIn) {
        $sql .= " WHERE user_id IS NOT NULL";
    }

    $stmt = $pdo->query($sql);
    $subs = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if (!$subs) {
        return 0;
    }

    $successCount = 0;
    foreach ($subs as $sub) {
        $ok = sendWebPush($sub, $payload);
        if ($ok) {
            $successCount++;
        }
    }

    return $successCount;
}
