'use strict';

function jsonResponse(res, data, status = 200) {
  const body = JSON.stringify(data);
  res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) });
  res.end(body);
}

// Body size limits:
//   DEFAULT_MAX: 1MB — standard text requests
//   LARGE_MAX:  16MB — chat endpoints that accept image attachments.
const BODY_LIMIT_DEFAULT = 1024 * 1024;
const BODY_LIMIT_LARGE = 16 * 1024 * 1024;

function readBody(req, opts = {}) {
  const maxBytes = opts.maxBytes || BODY_LIMIT_DEFAULT;
  return new Promise((resolve, reject) => {
    const chunks = [];
    let size = 0;
    let aborted = false;
    req.on('data', chunk => {
      if (aborted) return;
      size += chunk.length;
      if (size > maxBytes) {
        aborted = true;
        const err = new Error(`Body too large (>${Math.round(maxBytes / 1024 / 1024)}MB)`);
        err.code = 'BODY_TOO_LARGE';
        err.limit = maxBytes;
        req.on('data', () => {});
        reject(err);
        return;
      }
      chunks.push(chunk);
    });
    req.on('end', () => {
      if (aborted) return;
      try { resolve(JSON.parse(Buffer.concat(chunks).toString())); }
      catch { resolve({}); }
    });
    req.on('error', reject);
  });
}

function send413(res, err) {
  if (res.headersSent) return;
  const body = JSON.stringify({ error: err.message || 'Body too large', code: 'BODY_TOO_LARGE' });
  res.writeHead(413, {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(body),
    'Connection': 'close',
  });
  res.end(body);
}

function parseLimit(params, defaultVal = 50) {
  return Math.min(Math.max(parseInt(params.get('limit')) || defaultVal, 1), 500);
}

function parseOffset(params) {
  return Math.max(parseInt(params.get('offset')) || 0, 0);
}

function parseMultipart(buffer, boundary) {
  const result = {};
  const sep = Buffer.from('--' + boundary);
  let pos = 0;
  while (pos < buffer.length) {
    const start = buffer.indexOf(sep, pos);
    if (start === -1) break;
    const headerEnd = buffer.indexOf(Buffer.from('\r\n\r\n'), start);
    if (headerEnd === -1) break;
    const headerStr = buffer.slice(start + sep.length, headerEnd).toString();
    const bodyStart = headerEnd + 4;
    const nextBoundary = buffer.indexOf(sep, bodyStart);
    if (nextBoundary === -1) break;
    const afterBoundary = buffer.slice(nextBoundary + sep.length, nextBoundary + sep.length + 2).toString();
    const bodyEnd = nextBoundary - 2;
    const nameMatch = headerStr.match(/name="([^"]+)"/);
    if (nameMatch) {
      const name = nameMatch[1];
      result[name] = headerStr.includes('filename=')
        ? buffer.slice(bodyStart, bodyEnd)
        : buffer.slice(bodyStart, bodyEnd).toString().trim();
    }
    if (afterBoundary === '--') break;
    pos = nextBoundary;
  }
  return result;
}

module.exports = {
  BODY_LIMIT_DEFAULT,
  BODY_LIMIT_LARGE,
  jsonResponse,
  parseLimit,
  parseOffset,
  parseMultipart,
  readBody,
  send413,
};
