import { Inject, Injectable, Logger, OnModuleInit } from "@nestjs/common";
import PgBoss from "pg-boss";
import webpush from "web-push";
import { deletePushSubscription, processNotificationJob, type NotificationJob } from "@slackwsh/messaging";
import { PG_BOSS } from "./boss.provider";

function vapidConfigured(): boolean {
  return Boolean(process.env.VAPID_PUBLIC_KEY && process.env.VAPID_PRIVATE_KEY);
}

/**
 * Consumes the `notifications` queue enqueued transactionally alongside
 * message inserts (§4.3 / ADR-006). Decisioning lives in
 * `processNotificationJob`; this process only talks to the push service.
 */
@Injectable()
export class NotificationsProcessor implements OnModuleInit {
  private readonly logger = new Logger(NotificationsProcessor.name);

  constructor(@Inject(PG_BOSS) private readonly boss: PgBoss) {}

  async onModuleInit() {
    if (vapidConfigured()) {
      webpush.setVapidDetails(
        process.env.VAPID_SUBJECT ?? "mailto:security@localhost",
        process.env.VAPID_PUBLIC_KEY!,
        process.env.VAPID_PRIVATE_KEY!,
      );
    } else {
      this.logger.warn("VAPID keys missing — Web Push deliveries will be skipped");
    }

    await this.boss.work("notifications", async (jobs) => {
      for (const job of jobs) {
        const data = job.data as NotificationJob;
        const deliveries = await processNotificationJob(data);
        if (!vapidConfigured()) {
          this.logger.log(`notifications job ${job.id}: ${deliveries.length} delivery(ies) skipped (no VAPID)`);
          continue;
        }
        for (const delivery of deliveries) {
          try {
            await webpush.sendNotification(
              {
                endpoint: delivery.endpoint,
                keys: { p256dh: delivery.p256dh, auth: delivery.auth },
              },
              JSON.stringify(delivery.payload),
            );
          } catch (err: unknown) {
            const status = (err as { statusCode?: number }).statusCode;
            if (status === 404 || status === 410) {
              await deletePushSubscription(delivery.userId, delivery.endpoint).catch((deleteErr) =>
                this.logger.warn(`failed to drop dead push endpoint: ${String(deleteErr)}`),
              );
            } else {
              this.logger.warn(`web-push failed for job ${job.id}: ${String(err)}`);
            }
          }
        }
      }
    });
  }
}
