// src/chat/push.service.ts
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import * as webpush from 'web-push';
import { PushSubscription } from './entities/push-subscription.entity';

interface PushPayload {
  senderName: string;
  message: string;
  roomId: number;
}

@Injectable()
export class PushService implements OnModuleInit {
  private readonly logger = new Logger(PushService.name);
  private configured = false;

  constructor(
    @InjectDataSource('scheme_dbs')
    private readonly dataSource: DataSource,
  ) {}

  onModuleInit() {
    const pub  = process.env.VAPID_PUBLIC_KEY;
    const priv = process.env.VAPID_PRIVATE_KEY;
    const subj = process.env.VAPID_SUBJECT || 'mailto:admin@example.com';

    if (!pub || !priv) {
      this.logger.warn('⚠️  VAPID keys missing — push notifications disabled');
      return;
    }

    webpush.setVapidDetails(subj, pub, priv);
    this.configured = true;
    this.logger.log('✅ Push service configured');
  }

  // ── Save / upsert a subscription ─────────────────────────────────────────
  async subscribe(
    userId: number,
    endpoint: string,
    keys: { p256dh: string; auth: string },
  ): Promise<void> {
    const repo = this.dataSource.getRepository(PushSubscription);

    // Upsert: if endpoint already exists, update user_id & keys
    await this.dataSource.query(
      `INSERT INTO push_subscriptions (user_id, endpoint, p256dh, auth)
       VALUES (?, ?, ?, ?)
       ON DUPLICATE KEY UPDATE
         user_id = VALUES(user_id),
         p256dh  = VALUES(p256dh),
         auth    = VALUES(auth)`,
      [userId, endpoint, keys.p256dh, keys.auth],
    );

    this.logger.log(`Subscribed user ${userId} (endpoint ${endpoint.slice(0, 40)}…)`);
  }

  // ── Remove a subscription (e.g. on logout) ───────────────────────────────
  async unsubscribe(endpoint: string): Promise<void> {
    await this.dataSource
      .getRepository(PushSubscription)
      .delete({ endpoint });
  }

  // ── Send push to all of a user's devices ─────────────────────────────────
  async sendToUser(userId: number, payload: PushPayload): Promise<void> {
    if (!this.configured) return;

    const subs = await this.dataSource
      .getRepository(PushSubscription)
      .find({ where: { user_id: userId } });

    if (subs.length === 0) return;

    const body = JSON.stringify({
      title: payload.senderName || 'New message',
      body:  payload.message.length > 120
              ? payload.message.slice(0, 117) + '…'
              : payload.message,
      roomId: payload.roomId,
      tag:    `chat-room-${payload.roomId}`,
      url:    `/?room=${payload.roomId}`,
    });

    await Promise.all(
      subs.map(async (sub) => {
        try {
          await webpush.sendNotification(
            { endpoint: sub.endpoint, keys: { p256dh: sub.p256dh, auth: sub.auth } },
            body,
          );
        } catch (err: any) {
          // 404 = not found, 410 = gone — subscription is dead, clean up
          if (err.statusCode === 404 || err.statusCode === 410) {
            await this.unsubscribe(sub.endpoint);
            this.logger.log(`Removed dead subscription for user ${userId}`);
          } else {
            this.logger.error(
              `Push send failed for user ${userId}: ${err.statusCode} ${err.body || err.message}`,
            );
          }
        }
      }),
    );
  }
}