/**
 * Web Push Notification Sender
 * Sends push notifications to subscribed users
 */

import webpush from 'web-push'
import { getPushSubscriptionsByRoles, getPushSubscriptionsByUser, deletePushSubscription } from './pushDb'

// Configure web-push with VAPID keys
const vapidPublicKey = process.env.VAPID_PUBLIC_KEY || ''
const vapidPrivateKey = process.env.VAPID_PRIVATE_KEY || ''
const vapidSubject = process.env.VAPID_SUBJECT || 'mailto:support@logship.de'

if (vapidPublicKey && vapidPrivateKey) {
  webpush.setVapidDetails(
    vapidSubject,
    vapidPublicKey,
    vapidPrivateKey
  )
  console.log('[WebPush] ✅ VAPID configured successfully')
} else {
  console.warn('[WebPush] ⚠️  VAPID keys not configured - push notifications will not work')
}

interface PushPayload {
  title: string
  body: string
  icon?: string
  badge?: string
  url?: string
  data?: any
  // Topic groups notifications on the recipient device — newer messages with
  // the same topic replace older ones. Keep distinct per notification kind.
  topic?: string
}

/**
 * Send push notification to specific roles
 */
export const sendPushToRoles = async (roleIds: number[], payload: PushPayload) => {
  if (!vapidPublicKey || !vapidPrivateKey) {
    console.warn('[WebPush] Skipping push - VAPID not configured')
    return { sent: 0, failed: 0, removed: 0 }
  }

  try {
    // Get all subscriptions for these roles
    const subscriptions = getPushSubscriptionsByRoles(roleIds)

    if (subscriptions.length === 0) {
      console.log('[WebPush] No subscriptions found for roles:', roleIds)
      return { sent: 0, failed: 0, removed: 0 }
    }

    console.log(`[WebPush] Sending to ${subscriptions.length} subscribers for roles:`, roleIds)

    const results = {
      sent: 0,
      failed: 0,
      removed: 0
    }

    // Send to all subscriptions
    const promises = subscriptions.map(async (sub: any) => {
      try {
        const pushSubscription = {
          endpoint: sub.endpoint,
          keys: {
            p256dh: sub.p256dh,
            auth: sub.auth
          }
        }

        await webpush.sendNotification(
          pushSubscription,
          JSON.stringify(payload),
          {
            // Time-to-live: 24 hours (86400 seconds)
            TTL: 86400,
            // High urgency for immediate delivery even in background
            urgency: 'high',
            // Topic for notification grouping — newer pushes with the same
            // topic replace older ones on the device. Keep per-kind.
            topic: payload.topic || 'new-orders'
          }
        )

        results.sent++
        console.log('[WebPush] ✅ Sent to:', sub.endpoint.substring(0, 50) + '...')
      } catch (error: any) {
        console.error('[WebPush] ❌ Failed to send:', error.message)

        // Remove subscription if it's expired (410 Gone)
        if (error.statusCode === 410 || error.statusCode === 404) {
          console.log('[WebPush] Removing expired subscription:', sub.endpoint)
          deletePushSubscription(sub.endpoint)
          results.removed++
        } else {
          results.failed++
        }
      }
    })

    await Promise.all(promises)

    console.log('[WebPush] Results:', results)
    return results
  } catch (error: any) {
    console.error('[WebPush] ❌ Error sending push notifications:', error.message)
    return { sent: 0, failed: 0, removed: 0 }
  }
}

/**
 * Send a push notification to all of a single user's subscribed devices.
 * Used by the staff live-chat module to deliver a DM to a recipient who is
 * currently offline (no open WebSocket). Mirrors sendPushToRoles but keys on
 * user_id via getPushSubscriptionsByUser (already exists in pushDb — no schema
 * change). Self-contained: safe to no-op if VAPID isn't configured or the user
 * has no subscriptions.
 */
export const sendPushToUser = async (userId: number, payload: PushPayload) => {
  if (!vapidPublicKey || !vapidPrivateKey) {
    console.warn('[WebPush] Skipping push to user - VAPID not configured')
    return { sent: 0, failed: 0, removed: 0 }
  }

  try {
    const subscriptions = getPushSubscriptionsByUser(userId)
    if (!subscriptions || subscriptions.length === 0) {
      return { sent: 0, failed: 0, removed: 0 }
    }

    const results = { sent: 0, failed: 0, removed: 0 }

    const promises = subscriptions.map(async (sub: any) => {
      try {
        const pushSubscription = {
          endpoint: sub.endpoint,
          keys: { p256dh: sub.p256dh, auth: sub.auth }
        }
        await webpush.sendNotification(
          pushSubscription,
          JSON.stringify(payload),
          { TTL: 86400, urgency: 'high', topic: payload.topic || 'chat' }
        )
        results.sent++
      } catch (error: any) {
        if (error.statusCode === 410 || error.statusCode === 404) {
          deletePushSubscription(sub.endpoint)
          results.removed++
        } else {
          results.failed++
        }
      }
    })

    await Promise.all(promises)
    return results
  } catch (error: any) {
    console.error('[WebPush] ❌ Error sending push to user:', error.message)
    return { sent: 0, failed: 0, removed: 0 }
  }
}

/**
 * Build the payload for a chat direct-message push. Per-sender topic so a newer
 * DM from the same colleague replaces the older card on the device.
 */
export const buildChatMessagePayload = (
  senderName: string,
  body: string,
  senderUserId: number | string
): PushPayload => {
  const name = (senderName || '').trim() || 'Kollege'
  return {
    title: `💬 Neue Nachricht von ${name}`,
    body: (body || '').toString().trim().slice(0, 140) || 'Neue Nachricht',
    icon: '/favicon.ico',
    badge: '/favicon.ico',
    url: `/?chat=${senderUserId}`,
    topic: `chat-${senderUserId}`,
    data: {
      type: 'chat_message',
      senderUserId,
      timestamp: Date.now()
    }
  }
}

/**
 * Send push notification for new orders
 */
export const sendNewOrderNotification = async (roleIds: number[], orderCount: number, orderDetails?: any) => {
  const title = orderCount === 1 ? '🔔 New Order Received' : `🔔 ${orderCount} New Orders Received`
  const body = orderCount === 1
    ? 'You have 1 new order waiting to be processed'
    : `You have ${orderCount} new orders waiting to be processed`

  return sendPushToRoles(roleIds, {
    title,
    body,
    icon: '/favicon.ico',
    badge: '/favicon.ico',
    url: '/sales/orders',
    topic: 'new-orders',
    data: {
      type: 'new_orders',
      count: orderCount,
      timestamp: Date.now(),
      ...orderDetails
    }
  })
}

/**
 * Build the shared payload for a ticket-handoff notification. Used by both the
 * web-push send and the in-app SSE/toast publisher so the user gets a
 * consistent message regardless of which channel reaches them first.
 */
export const buildRequestActionPayload = (
  action: 'merchant-action' | 'support-action',
  ticket: { id: number | string, docNo: string, summary: string, orgName?: string, lastMessage?: string }
): PushPayload => {
  const isMerchant = action === 'merchant-action'
  const docLabel = `#${ticket.docNo}`
  const title = isMerchant
    ? `🎫 Ticket ${docLabel} — Ihre Aktion erforderlich`
    : `🎫 Ticket ${docLabel} — ${(ticket.orgName || '').trim() || 'Merchant'} hat geantwortet`
  const fallback = isMerchant
    ? 'Auf Ihr Ticket wird eine Rückmeldung benötigt.'
    : 'Der Merchant hat auf ein Ticket reagiert.'
  // Prefer the most recent update message (the one the user just entered) so the
  // toast reflects the latest reply; fall back to the ticket summary, then a
  // generic line.
  const body = ((ticket.lastMessage || '').trim() || (ticket.summary || '').trim()).slice(0, 140) || fallback
  const url = isMerchant
    ? `/requests/my-tickets/${ticket.id}`
    : `/requests/requests/${ticket.id}/edit`

  return {
    title,
    body,
    icon: '/favicon.ico',
    badge: '/favicon.ico',
    url,
    // Per-ticket topic so a later push for the same ticket replaces the
    // older one on the device (no duplicate cards stacking up).
    topic: `request-${ticket.id}`,
    data: {
      type: isMerchant ? 'request_merchant_action' : 'request_support_action',
      ticketId: ticket.id,
      docNo: ticket.docNo,
      timestamp: Date.now()
    }
  }
}

/**
 * Send push notification for a ticket handoff between merchant and support.
 * Mirrors the email path in `requests/[id]/action-notification.post.ts`:
 *   - 'merchant-action' → support assigned the ticket to the merchant
 *   - 'support-action'  → merchant replied; ticket is back with support
 * The caller decides which role IDs receive the push (see route — uses the
 * org→role access map so only users whose role can access the ticket's org
 * are reached).
 */
export const sendRequestActionNotification = async (
  roleIds: number[],
  action: 'merchant-action' | 'support-action',
  ticket: { id: number | string, docNo: string, summary: string, orgName?: string, lastMessage?: string }
) => {
  return sendPushToRoles(roleIds, buildRequestActionPayload(action, ticket))
}
