/*!
 * Copyright(c) 2018 Jan Blaha
 *
 * Collect and serve logs with request scope
 */

const os = require('os')

function paddingRight (str, length) {
  const padding = (new Array(Math.max(length - str.length + 1, 0))).join(' ')
  return str + padding
}

function logsToFormattedString (logs) {
  const start = logs[0].timestamp
  return logs.map((m) => {
    const time = (m.timestamp - start)
    const paddedTime = paddingRight(time + '', 7)
    return '+' + paddedTime + m.message
  }).join(os.EOL)
}

function cutResponseHeader (logs, maxLogResponseHeaderSize, logger) {
  let headerSize = 4
  const logsCut = []
  for (let i = 0; i < logs.length && headerSize < maxLogResponseHeaderSize; i++) {
    const log = logs[i]
    headerSize += JSON.stringify(log).length + 2
    if (headerSize < maxLogResponseHeaderSize) {
      logsCut.push(logs[i])
    }
  }

  if (logsCut.length !== logs.length) {
    logger.warn('The size of the debug logs which should have been written to the response header exceeded the limit. The content of the response header ' +
    ' was cut to avoid HPE_HEADER_OVERFLOW errors. To avoid this message, please decrease the number of console.log calls in the template.')
    logsCut.push({
      timestamp: new Date(),
      level: 'warn',
      message: 'The further logs have been cut to prevent HPE_HEADER_OVERFLOW error. You can set request.options.debug.logsToResponse=true to read full logs in the output stream.'
    })
  }

  return logsCut
}

module.exports = function (reporter, definition) {
  reporter.options.debug = Object.assign({}, { maxLogResponseHeaderSize: 60 * 1024 }, definition.options)
  reporter.initializeListeners.add('request-log', () => {
    reporter.renderErrorListeners.add('request-log', (request, res, e) => {
      if (request.options.debug && request.options.debug.logsToResponse) {
        e.message += os.EOL + 'logs' + (request.options.isChildRequest ? ' (child request):' : ':') + os.EOL + logsToFormattedString(request.context.logs)
      }
    })

    reporter.afterRenderListeners.add('request-log', (request, response) => {
      if (request.options.isChildRequest) {
        return
      }

      if (request.options.debug && request.options.debug.logsToResponseHeader && response.meta.headers) {
        response.meta.headers['Debug-Logs'] = JSON.stringify(cutResponseHeader(request.context.logs, reporter.options.debug.maxLogResponseHeaderSize, reporter.logger))
      }

      if (request.options.debug && request.options.debug.logsToResponse) {
        if (response.meta.headers) {
          response.meta.headers['Content-Type'] = 'text/plain'
          response.meta.headers['Content-Disposition'] = 'inline; filename="log.txt"'
          response.meta.headers['File-Extension'] = 'txt'
        }

        response.content = Buffer.from(logsToFormattedString(request.context.logs))
      }
    })
  })
}

@@ -2210,32 +2210,279 @@
 urn%0D%0A      %7D%0D%0A%0D%0A
+      request.context.logs.push(%7B%0D%0A        message: %60Rendering request $%7Brequest.context.id%7D finished in $%7B(new Date().getTime() - request.context.startTimestamp)%7D ms%60,%0D%0A        timestamp: new Date().getTime(),%0D%0A        level: 'info'%0D%0A      %7D)%0D%0A%0D%0A
       if (reques

add rendering request finished line to output logs