/**
 * public/sw-push.js — Pure push notification helpers (no SW globals).
 *
 * This file is imported by public/sw.js (module service worker) and tested
 * directly by test/sw-push.test.ts. It must never reference `self`, `clients`,
 * or any other SW-specific global — pure functions only.
 *
 * Implements the §3.3 PushPayload contract (one shape; FE reads `cls`).
 * SEC-M6: tag = sessionId so the browser deduplicates (no notification stacking).
 * SEC-C1: capability token is forwarded in the decision body; Origin + token
 *         validation happens server-side at POST /hook/decision.
 */

/** @type {Record<string, string>} */
const TITLES = {
  'needs-input': 'Approval Needed',
  done: 'Task Complete',
  stuck: 'Task Stuck',
  budget: 'Cost Budget Reached',
}

/**
 * Build a Notification title + options from an incoming push payload.
 *
 * @param {{ sessionId: string, toolName?: string, detail?: string, token?: string, cls: string }} payload
 * @returns {{ title: string, options: Record<string, unknown> }}
 */
export function buildPushNotification(payload) {
  const { sessionId, toolName, detail, token, cls } = payload

  const title = TITLES[cls] ?? 'Web Terminal'

  // Body: prefer explicit detail, fall back to toolName hint, else omit.
  const body = detail ?? (toolName ? `Tool: ${toolName}` : undefined)

  /** @type {Record<string, unknown>} */
  const options = {
    tag: sessionId, // SEC-M6: replaces any previous notification for this session
    body,
    data: { sessionId, token, cls },
    requireInteraction: cls === 'needs-input',
    // Allow / Deny actions only for needs-input (lock-screen approval, AC-A1.2/A1.3)
    actions:
      cls === 'needs-input'
        ? [
            { action: 'allow', title: 'Allow' },
            { action: 'deny', title: 'Deny' },
          ]
        : [],
  }

  return { title, options }
}

/**
 * Resolve a notificationclick event into an opaque result.
 * The caller (sw.js) executes the result:
 *   kind='decision' → POST /hook/decision with result.body (SEC-C1)
 *   kind='focus'    → openWindow / focus existing tab at result.url
 *
 * @param {{ data: { sessionId?: string, token?: string, cls?: string } | null }} notification
 * @param {string | null | undefined} action — event.action from notificationclick
 * @returns {{ kind: 'decision', body: string } | { kind: 'focus', url: string }}
 */
export function resolveNotificationClick(notification, action) {
  const data = notification?.data ?? {}
  const { sessionId = '', token } = /** @type {{ sessionId?: string, token?: string }} */ (data)

  if (action === 'allow' || action === 'deny') {
    // SEC-C1: include capability token so server can authenticate this decision.
    // Origin header is added automatically by fetch() with credentials:'same-origin'.
    return {
      kind: 'decision',
      body: JSON.stringify({ sessionId, decision: action, token }),
    }
  }

  // Default (body click, empty string, undefined, null) → focus/open terminal session
  return {
    kind: 'focus',
    url: `/?session=${encodeURIComponent(sessionId)}`,
  }
}
