import { captureCaught } from '@/server/observability/capture.server';

/**
 * Body-size-guarded JSON reader.
 *
 * Checks Content-Length header first (fast path), then enforces a byte cap
 * after reading, preventing multi-GB body attacks before any parsing happens.
 *
 * Usage:
 *   import { respondError } from '@/server/api/error-envelope.js';
 *   const result = await readJsonBody<MyType>(request);
 *   if (!result.ok) {
 *     return result.error === 'too_large'
 *       ? respondError('BODY_TOO_LARGE', 'Body too large', 413)
 *       : respondError('INVALID_BODY', 'Invalid JSON', 400);
 *   }
 *   const data = result.data; // T
 */

export async function readJsonBody<T = unknown>(
  request: Request,
  maxBytes = 64 * 1024,
): Promise<
  { ok: true; data: T; raw: string } | { ok: false; error: 'too_large' | 'invalid_json' }
> {
  const len = request.headers.get('content-length');
  if (len && Number(len) > maxBytes) return { ok: false, error: 'too_large' };

  let text: string;
  try {
    text = await request.text();
  } catch (err) {
    captureCaught(err, { scope: 'server.utils.read-body', severity: 'warning' });
    return { ok: false, error: 'invalid_json' };
  }

  if (text.length > maxBytes) return { ok: false, error: 'too_large' };

  try {
    return { ok: true, data: JSON.parse(text) as T, raw: text };
  } catch (err) {
    captureCaught(err, { scope: 'server.utils.read-body', severity: 'warning' });
    return { ok: false, error: 'invalid_json' };
  }
}
