// Self-service push-notification management for the logged-in user (any role).
// Mounted under /auth/me behind requireAuth, so req.user is the fresh DB row.
// Devices (endpoints) and stream subscriptions live here; the fan-out that
// actually delivers is utils/pushDispatch. See docs/android/PLAN.md §11.

const pushDevices = require('../../../model/pushDevices/pushDevices.model')
const notificationSubs = require('../../../model/notificationSubs/notificationSubs.model')
const registries = require('../../../modules/registries')
const { isAllowedEndpoint } = require('../../../utils/pushDispatch')

const log = require('../../../utils/logger')('notifications')

// POST /auth/me/devices — register (or refresh) a push endpoint for this user.
async function registerDevice(req, res) {
  const { transport = 'unifiedpush', endpoint, platform } = req.body
  // SSRF guard: the endpoint is a URL the server will later POST to. Reject
  // anything that isn't an allowed HTTPS relay origin before storing it.
  if (!isAllowedEndpoint(endpoint)) {
    return res.status(400).json({ message: 'Endpoint is not an allowed push URL' })
  }
  try {
    const device = await pushDevices.register({ userId: req.user.id, transport, endpoint, platform })
    return res.status(201).json(device)
  } catch (err) {
    log.error('registerDevice', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /auth/me/devices — this user's registered devices.
async function listDevices(req, res) {
  try {
    return res.json(await pushDevices.listForUser(req.user.id))
  } catch (err) {
    log.error('listDevices', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// DELETE /auth/me/devices/:id — unregister a device (must belong to the caller).
async function removeDevice(req, res) {
  try {
    const ok = await pushDevices.remove(Number(req.params.id), req.user.id)
    if (!ok) return res.status(404).json({ message: 'Not found' })
    return res.json({ ok: true })
  } catch (err) {
    log.error('removeDevice', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /auth/me/notifications/streams — the subscribable catalog: core's streams
// plus every installed module's, in registration order. Fixed for the lifetime of
// a process (registration is boot-time), not a static constant.
function getStreams(req, res) {
  return res.json({ streams: registries.allStreams() })
}

// GET /auth/me/notifications/subscriptions — the caller's opted-in stream ids.
async function getSubscriptions(req, res) {
  try {
    return res.json({ streams: await notificationSubs.getForUser(req.user.id) })
  } catch (err) {
    log.error('getSubscriptions', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// PUT /auth/me/notifications/subscriptions — replace the caller's stream set.
// Unknown ids are dropped; the stored (cleaned) set is echoed back.
async function putSubscriptions(req, res) {
  try {
    const streams = await notificationSubs.setForUser(req.user.id, req.body.streams)
    return res.json({ streams })
  } catch (err) {
    log.error('putSubscriptions', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

module.exports = {
  registerDevice,
  listDevices,
  removeDevice,
  getStreams,
  getSubscriptions,
  putSubscriptions,
}
