text: const path = require('path')
  const fs = require('fs').promises
  const fetch = require('node-fetch')
  const prettyMs = require('pretty-ms')
  const logger = require('./util/logger')
  const prettyBytes = require('pretty-bytes')
  const { benchTitle } = require('./constants')
  
  const gzipIgnoreRegex = new RegExp(`(General|^Serverless|${benchTitle})`)
  
  const prettify = (val, type = 'bytes') => {
    if (typeof val !== 'number') return 'N/A'
    return type === 'bytes' ? prettyBytes(val) : prettyMs(val)
  }
  
  const round = (num, places) => {
    const placesFactor = Math.pow(10, places)
    return Math.round(num * placesFactor) / placesFactor
  }
  
  const shortenLabel = (itemKey) =>
    itemKey.length > 24
      ? `${itemKey.substr(0, 12)}..${itemKey.substr(itemKey.length - 12, 12)}`
      : itemKey
  
  const twoMB = 2 * 1024 * 1024
  
  module.exports = async function addComment(
    results = [],
    actionInfo,
    statsConfig
  ) {
    let comment = `# ${
      actionInfo.isRelease
        ? statsConfig.commentReleaseHeading || 'Stats from current release'
        : statsConfig.commentHeading || 'Stats from current PR'
    }\n\n`
  
    const tableHead = `|  | ${statsConfig.mainRepo} ${statsConfig.mainBranch} ${
      actionInfo.lastStableTag || ''
    } | ${actionInfo.prRepo} ${actionInfo.prRef} | Change |\n| - | - | - | - |\n`
  
    for (let i = 0; i < results.length; i++) {
      const result = results[i]
      const isLastResult = i === results.length - 1
      let resultHasIncrease = false
      let resultHasDecrease = false
      let resultContent = ''
  
      Object.keys(result.mainRepoStats).forEach((groupKey) => {
        const isBenchmark = groupKey === benchTitle
        const mainRepoGroup = result.mainRepoStats[groupKey]
        const diffRepoGroup = result.diffRepoStats[groupKey]
        const itemKeys = new Set([
          ...Object.keys(mainRepoGroup),
          ...Object.keys(diffRepoGroup),
        ])
        let groupTable = tableHead
        let mainRepoTotal = 0
        let diffRepoTotal = 0
        let totalChange = 0
  
        itemKeys.forEach((itemKey) => {
          const prettyType = itemKey.match(/(length|duration)/i) ? 'ms' : 'bytes'
          const isGzipItem = itemKey.endsWith('gzip')
          const mainItemVal = mainRepoGroup[itemKey]
          const diffItemVal = diffRepoGroup[itemKey]
          const useRawValue = isBenchmark && prettyType !== 'ms'
          const mainItemStr = useRawValue
            ? mainItemVal
            : prettify(mainItemVal, prettyType)
  
          const diffItemStr = useRawValue
            ? diffItemVal
            : prettify(diffItemVal, prettyType)
  
          let change = '✓'
  
          // Don't show gzip values for serverless as they aren't
          // deterministic currently
          if (groupKey.startsWith('Serverless') && isGzipItem) return
          // otherwise only show gzip values
          else if (!isGzipItem && !groupKey.match(gzipIgnoreRegex)) return
  
          if (
            itemKey !== 'buildDuration' ||
            (isBenchmark && itemKey.match(/req\/sec/))
          ) {
            if (typeof mainItemVal === 'number') mainRepoTotal += mainItemVal
            if (typeof diffItemVal === 'number') diffRepoTotal += diffItemVal
          }
  
          // calculate the change
          if (mainItemVal !== diffItemVal) {
            if (
              typeof mainItemVal === 'number' &&
              typeof diffItemVal === 'number'
            ) {
              change = round(diffItemVal - mainItemVal, 2)
  
              // check if there is still a change after rounding
              if (change !== 0) {
                const absChange = Math.abs(change)
                const warnIfNegative = isBenchmark && itemKey.match(/req\/sec/)
                const warn = warnIfNegative
                  ? change < 0
                    ? '⚠️ '
                    : ''
                  : change > 0
                  ? '⚠️ '
                  : ''
                change = `${warn}${change < 0 ? '-' : '+'}${
                  useRawValue ? absChange : prettify(absChange, prettyType)
                }`
              }
            } else {
              change = 'N/A'
            }
          }
  
          groupTable += `| ${
            isBenchmark ? itemKey : shortenLabel(itemKey)
          } | ${mainItemStr} | ${diffItemStr} | ${change} |\n`
        })
        let groupTotalChange = ''
  
        totalChange = diffRepoTotal - mainRepoTotal
  
        if (totalChange !== 0) {
          if (totalChange < 0) {
            resultHasDecrease = true
            groupTotalChange = ` Overall decrease ${isBenchmark ? '⚠️' : '✓'}`
          } else {
            if (
              (groupKey !== 'General' && totalChange > 5) ||
              totalChange > twoMB
            ) {
              resultHasIncrease = true
            }
            groupTotalChange = ` Overall increase ${isBenchmark ? '✓' : '⚠️'}`
          }
        }
  
        if (groupKey !== 'General' && groupKey !== benchTitle) {
          let totalChangeSign = ''
  
          if (totalChange === 0) {
            totalChange = '✓'
          } else {
            totalChangeSign = totalChange < 0 ? '-' : '⚠️ +'
          }
          totalChange = `${totalChangeSign}${
            typeof totalChange === 'number'
              ? prettify(Math.abs(totalChange))
              : totalChange
          }`
          groupTable += `| Overall change | ${prettyBytes(
            round(mainRepoTotal, 2)
          )} | ${prettyBytes(round(diffRepoTotal, 2))} | ${totalChange} |\n`
        }
  
        if (itemKeys.size > 0) {
          resultContent += `<details>\n`
          resultContent += `<summary><strong>${groupKey}</strong>${groupTotalChange}</summary>\n\n`
          resultContent += groupTable
          resultContent += `\n</details>\n\n`
        }
      })
  
      // add diffs
      if (result.diffs) {
        const diffHeading = '#### Diffs\n'
        let diffContent = diffHeading
  
        Object.keys(result.diffs).forEach((itemKey) => {
          const curDiff = result.diffs[itemKey]
          diffContent += `<details>\n`
          diffContent += `<summary>Diff for <strong>${shortenLabel(
            itemKey
          )}</strong></summary>\n\n`
  
          if (curDiff.length > 36 * 1000) {
            diffContent += 'Diff too large to display'
          } else {
            diffContent += `\`\`\`diff\n${curDiff}\n\`\`\``
          }
          diffContent += `\n</details>\n`
        })
  
        if (diffContent !== diffHeading) {
          resultContent += diffContent
        }
      }
      let increaseDecreaseNote = ''
  
      if (resultHasIncrease) {
        increaseDecreaseNote = ' (Increase detected ⚠️)'
      } else if (resultHasDecrease) {
        increaseDecreaseNote = ' (Decrease detected ✓)'
      }
  
      comment += `<details>\n`
      comment += `<summary><strong>${result.title}</strong>${increaseDecreaseNote}</summary>\n\n<br/>\n\n`
      comment += resultContent
      comment += '</details>\n'
  
      if (!isLastResult) {
        comment += `<hr/>\n`
      }
    }
    if (process.env.LOCAL_STATS) {
      const statsPath = path.resolve('pr-stats.md')
      await fs.writeFile(statsPath, comment)
      console.log(`Output PR stats to ${statsPath}`)
    } else {
      logger('\n--stats start--\n', comment, '\n--stats end--\n')
    }
  
    if (
      actionInfo.customCommentEndpoint ||
      (actionInfo.githubToken && actionInfo.commentEndpoint)
    ) {
      logger(`Posting results to ${actionInfo.commentEndpoint}`)
  
      const body = {
        body: comment,
        ...(!actionInfo.githubToken
          ? {
              isRelease: actionInfo.isRelease,
              commitId: actionInfo.commitId,
              issueId: actionInfo.issueId,
            }
          : {}),
      }
  
      if (actionInfo.customCommentEndpoint) {
        logger(`Using body ${JSON.stringify({ ...body, body: 'OMITTED' })}`)
      }
  
      try {
        const res = await fetch(actionInfo.commentEndpoint, {
          method: 'POST',
          headers: {
            ...(actionInfo.githubToken
              ? {
                  Authorization: `bearer ${actionInfo.githubToken}`,
                }
              : {
                  'content-type': 'application/json',
                }),
          },
          body: JSON.stringify(body),
        })
  
        if (!res.ok) {
          logger.error(`Failed to post results ${res.status}`)
          try {
            logger.error(await res.text())
          } catch (_) {
            /* no-op */
          }
        } else {
          logger('Successfully posted results')
        }
      } catch (err) {
        logger.error(`Error occurred posting results`, err)
      }
    } else {
      logger(
        `Not posting results`,
        actionInfo.githubToken ? 'No comment endpoint' : 'no GitHub token'
      )
    }
  }
  