<?php

namespace PloverCRM\Modules\PushNotifications\Services;

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

/**
 * Web Push Sender Service
 * 
 * Sends push notifications to web browsers via the Web Push protocol.
 */
class WebPushSender
{
  private const VAPID_OPTION_KEY = 'plover_crm_vapid_keys';

  /**
   * Send a web push notification to all subscribed browsers
   *
   * @param string $title Notification title
   * @param string $body Notification body
   * @param array $data Additional data (e.g. subscriber_id, url)
   */
  public static function send(string $title, string $body, array $data = []): void
  {
    $vapid = get_option(self::VAPID_OPTION_KEY);

    if (!$vapid || empty($vapid['publicKey']) || empty($vapid['privateKey'])) {
      return;
    }

    $subscriptions = self::getAllSubscriptions();

    if (empty($subscriptions)) {
      return;
    }

    $auth = [
      'VAPID' => [
        'subject' => get_site_url(),
        'publicKey' => $vapid['publicKey'],
        'privateKey' => $vapid['privateKey'],
      ],
    ];

    try {
      $webPush = new WebPush($auth);

      $payload = json_encode([
        'title' => $title,
        'body' => $body,
        'data' => $data,
        'icon' => '/favicon.ico',
      ]);

      foreach ($subscriptions as $sub) {
        $subscription = Subscription::create([
          'endpoint' => $sub->endpoint,
          'keys' => [
            'p256dh' => $sub->p256dh,
            'auth' => $sub->auth,
          ],
        ]);

        $webPush->queueNotification($subscription, $payload);
      }

      // Flush and handle expired subscriptions
      $expiredIds = [];

      foreach ($webPush->flush() as $report) {
        if (!$report->isSuccess()) {
          $statusCode = $report->getResponse()?->getStatusCode();
          // 404 or 410 means the subscription is no longer valid
          if ($statusCode === 404 || $statusCode === 410) {
            $endpoint = $report->getRequest()->getUri()->__toString();
            $id = self::getSubscriptionIdByEndpoint($endpoint);
            if ($id) {
              $expiredIds[] = $id;
            }
          }
        }
      }

      // Clean up expired subscriptions
      if (!empty($expiredIds)) {
        self::deleteSubscriptions($expiredIds);
      }
    } catch (\Exception $e) {
      error_log('PloverCRM WebPush error: ' . $e->getMessage());
    }
  }

  /**
   * Get all web push subscriptions
   */
  private static function getAllSubscriptions(): array
  {
    global $wpdb;
    $table = $wpdb->prefix . 'plover_crm_web_push_subscriptions';

    return $wpdb->get_results("SELECT * FROM $table");
  }

  /**
   * Get subscription ID by endpoint URL
   */
  private static function getSubscriptionIdByEndpoint(string $endpoint): ?int
  {
    global $wpdb;
    $table = $wpdb->prefix . 'plover_crm_web_push_subscriptions';

    $id = $wpdb->get_var($wpdb->prepare(
      "SELECT id FROM $table WHERE endpoint = %s LIMIT 1",
      $endpoint
    ));

    return $id ? (int) $id : null;
  }

  /**
   * Delete subscriptions by IDs
   */
  private static function deleteSubscriptions(array $ids): void
  {
    global $wpdb;
    $table = $wpdb->prefix . 'plover_crm_web_push_subscriptions';

    $placeholders = implode(',', array_fill(0, count($ids), '%d'));
    $wpdb->query($wpdb->prepare(
      "DELETE FROM $table WHERE id IN ($placeholders)",
      ...$ids
    ));
  }
}
