const DocArchiveManager = require('../app/js/DocArchiveManager').promises
const MongoManager = require('../app/js/MongoManager').promises
const { getCollection, ObjectId } = require('../app/js/mongodb')
const minimist = require('minimist')

async function worker(projectId) {
  try {
    // see if the project needs to be unarchived, and unarchive it
    const archivedDocs = await MongoManager.getArchivedProjectDocs(projectId)
    if (archivedDocs.length) {
      await DocArchiveManager.unArchiveAllDocs(projectId)
    }

    // get the doc content so we can validate it
    const docs = await MongoManager.getProjectsDocs(
      projectId,
      { include_deleted: false },
      { lines: 1 }
    )

    // start archiving in the background while we check the content, if it was archived to begin with
    let archivePromise
    if (archivedDocs.length) {
      archivePromise = DocArchiveManager.archiveAllDocs(projectId)
    }

    let warning = false

    // validate the doc contents and log any warnings to investigate later
    for (const doc of docs) {
      if (!doc.lines) {
        warning = true
        console.error('WARN:', projectId, doc._id, 'has no content')
      }
      // eslint-disable-next-line no-control-regex
      if (doc.lines && doc.lines.some((line) => line.match(/(\r|\u0000)/))) {
        warning = true
        console.error('WARN:', projectId, doc._id, 'has invalid characters')
      }
    }

    // ensure the archive process has finished
    if (archivePromise) {
      await archivePromise
    }

    if (!warning) {
      // log to stderr along with the other output
      console.error('OK:', projectId)
    }
  } catch (err) {
    console.error('ERROR:', projectId, err)
  }
}

async function rearchiveAllDocs() {
  const params = minimist(process.argv.slice(2))
  const maxWorkers = params.w || 1
  console.log(`Starting with ${maxWorkers} workers`)

  // start from an objectId and run in ascending order, so we can resume later
  const query = {}
  const startId = params._[0]
  if (startId) {
    const validator = new RegExp('^[0-9a-fA-F]{24}$')
    if (!validator.test(startId)) {
      console.error('Invalid object id')
      return
    }
    query._id = {
      $gt: ObjectId(startId)
    }
    console.log(`Starting from object ID ${startId}`)
  } else {
    console.log('No object id specified. Starting from the beginning.')
  }

  const results = (await getCollection('projects'))
    .find(query, { _id: 1 })
    .sort({ _id: 1 })
  let jobCount = 0

  // keep going until we run out of projects
  while (true) {
    // get a new project to run a job with
    const project = await results.next()
    // if there are no more projects, wait until all the jobs have finished and exit
    if (!project) {
      // eslint-disable-next-line no-unmodified-loop-condition
      while (jobCount) {
        await new Promise((resolve) => setTimeout(resolve, 50))
      }
      return
    }

    // wait until there are fewer than maxWorkers jobs running
    // eslint-disable-next-line no-unmodified-loop-condition
    while (jobCount >= maxWorkers) {
      await new Promise((resolve) => setTimeout(resolve, 50))
    }

    // start a new job in the background and then continue the loop
    ++jobCount
    worker(project._id)
      .then(() => --jobCount)
      .catch(() => {
        console.error('ERROR:', project._id)
        --jobCount
      })
  }
}

if (!module.parent) {
  rearchiveAllDocs()
    .then(() => {
      console.log('Finished!')
      process.exit(0)
    })
    .catch((err) => {
      console.error('Something went wrong:', err)
      process.exit(1)
    })
}

@@ -2018,16 +2018,41 @@
 ms._%5B0%5D%0A
+  const endId = params.e%0A
   if (st
@@ -2068,26 +2068,13 @@
     
-const validator = 
+if (!
 new 
@@ -2104,27 +2104,8 @@
 %7D$')
-%0A    if (!validator
 .tes
@@ -2120,33 +2120,35 @@
 d)) %7B%0A      
-console.e
+throw new E
 rror('Invali
@@ -2149,16 +2149,22 @@
 Invalid 
+start 
 object i
@@ -2167,29 +2167,16 @@
 ct id')%0A
-      return%0A
     %7D%0A  
@@ -2200,16 +2200,17 @@
      $gt
+e
 : Object
@@ -2369,16 +2369,296 @@
 ')%0A  %7D%0A%0A
+  if (endId) %7B%0A    if (!new RegExp('%5E%5B0-9a-fA-F%5D%7B24%7D$').test(endId)) %7B%0A      throw new Error('Invalid end object id')%0A    %7D%0A    query._id = %7B%0A      ...(query._id %7C%7C %7B%7D),%0A      ...%7B%0A        $lte: ObjectId(endId)%0A      %7D%0A    %7D%0A    console.log(%60Stopping at object ID $%7BendId%7D%60)%0A  %7D%0A%0A
   const 

Add 'endId' parameter to rearchive script