'use strict';

const pushStore = require('./mobile-push-store');
const { readJsonBody } = require('./mobile-auth-api');

function sendJson(res, status, payload) {
  res.writeHead(status, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify(payload));
}

function errorJson(res, status, code, message) {
  sendJson(res, status, { ok: false, error: code, message: message || code });
}

function requireDeviceAuth(auth) {
  if (!auth?.authenticated || auth.isLoopback || !auth.deviceId) throw new Error('device_token_required');
  return auth;
}

function publicSettings(settings) {
  return {
    enabled: !!settings.enabled,
    include_preview: !!settings.include_preview,
    quiet_start: settings.quiet_start || '',
    quiet_end: settings.quiet_end || '',
    quiet_suppresses_high: !!settings.quiet_suppresses_high,
    finished_min_runtime_ms: Number(settings.finished_min_runtime_ms || 0),
    updated_at: Number(settings.updated_at || 0),
  };
}

async function handleMobilePushApi(req, res, url, options = {}) {
  const db = options.db;
  if (!db) return false;
  pushStore.ensureMobilePushSchema(db);

  try {
    if (url.pathname === '/api/push/vapid-public-key' && req.method === 'GET') {
      sendJson(res, 200, {
        ok: true,
        public_key: options.dispatcher?.getVapidPublicKey?.() || '',
      });
      return true;
    }

    if (url.pathname === '/api/push/settings' && req.method === 'GET') {
      const auth = requireDeviceAuth(options.auth);
      sendJson(res, 200, {
        ok: true,
        settings: publicSettings(pushStore.getPushSettings(db, auth.deviceId)),
        subscriptions: pushStore.listDeviceSubscriptions(db, auth.deviceId),
      });
      return true;
    }

    if (url.pathname === '/api/push/settings' && req.method === 'PUT') {
      const auth = requireDeviceAuth(options.auth);
      const body = await readJsonBody(req, 64 * 1024);
      const settings = pushStore.updatePushSettings(db, auth.deviceId, body.settings || body);
      sendJson(res, 200, { ok: true, settings: publicSettings(settings) });
      return true;
    }

    if (url.pathname === '/api/push/subscribe' && req.method === 'POST') {
      const auth = requireDeviceAuth(options.auth);
      const body = await readJsonBody(req, 256 * 1024);
      const subscription = pushStore.upsertPushSubscription(db, auth.deviceId, body.subscription || body, {
        userAgent: req.headers?.['user-agent'] || '',
      });
      sendJson(res, 200, {
        ok: true,
        subscription,
        settings: publicSettings(pushStore.getPushSettings(db, auth.deviceId)),
      });
      return true;
    }

    if (url.pathname === '/api/push/subscribe' && req.method === 'DELETE') {
      const auth = requireDeviceAuth(options.auth);
      const body = await readJsonBody(req, 64 * 1024).catch(() => ({}));
      const deleted = pushStore.deletePushSubscription(db, auth.deviceId, { endpoint: body.endpoint || '' });
      sendJson(res, 200, { ok: true, deleted });
      return true;
    }

    const subscriptionDelete = url.pathname.match(/^\/api\/push\/subscribe\/([^/]+)$/);
    if (subscriptionDelete && req.method === 'DELETE') {
      const auth = requireDeviceAuth(options.auth);
      const deleted = pushStore.deletePushSubscription(db, auth.deviceId, {
        id: decodeURIComponent(subscriptionDelete[1]),
      });
      sendJson(res, 200, { ok: true, deleted });
      return true;
    }

    if (url.pathname === '/api/push/test' && req.method === 'POST') {
      const auth = requireDeviceAuth(options.auth);
      const result = await options.dispatcher.sendTestToDevice(auth.deviceId);
      sendJson(res, 200, { ok: true, result });
      return true;
    }
  } catch (err) {
    const code = err && err.message ? err.message : 'push_error';
    const status = /device_token_required|step_up_required/.test(code) ? 403
      : /required|invalid|too_large|https/.test(code) ? 400
      : 500;
    errorJson(res, status, code);
    return true;
  }

  return false;
}

module.exports = { handleMobilePushApi };
