const { Project } = require('../../models/Project')
const ProjectDetailsHandler = require('./ProjectDetailsHandler')
const HistoryManager = require('../History/HistoryManager')
const ProjectEntityUpdateHandler = require('./ProjectEntityUpdateHandler')
const { callbackify } = require('util')

const ProjectHistoryHandler = {
  async setHistoryId(projectId, historyId) {
    // reject invalid history ids
    if (historyId == null) {
      throw new Error('missing history id')
    }

    // use $exists:false to prevent overwriting any existing history id, atomically
    const result = await Project.updateOne(
      { _id: projectId, 'overleaf.history.id': { $exists: false } },
      { 'overleaf.history.id': historyId }
    )

    if (result.matchedCount === 0) {
      throw new Error('history exists')
    }
  },

  async getHistoryId(projectId) {
    const project = await ProjectDetailsHandler.promises.getDetails(projectId)
    return project?.overleaf?.history?.id
  },

  async ensureHistoryExistsForProject(projectId) {
    // We can only set a history id for a project that doesn't have one. The
    // history id is cached in the project history service, and changing an
    // existing value corrupts the history, leaving it in an irrecoverable
    // state. Setting a history id when one wasn't present before is ok,
    // because undefined history ids aren't cached.
    let historyId = await ProjectHistoryHandler.getHistoryId(projectId)

    if (historyId != null) {
      return
    }

    historyId = await HistoryManager.promises.initializeProject(projectId)
    if (historyId == null) {
      throw new Error('failed to initialize history id')
    }

    await ProjectHistoryHandler.setHistoryId(projectId, historyId)

    await ProjectEntityUpdateHandler.promises.resyncProjectHistory(
      projectId,
      {}
    )

    await HistoryManager.promises.flushProject(projectId)
  },
}

module.exports = {
  setHistoryId: callbackify(ProjectHistoryHandler.setHistoryId),
  getHistoryId: callbackify(ProjectHistoryHandler.getHistoryId),
  ensureHistoryExistsForProject: callbackify(
    ProjectHistoryHandler.ensureHistoryExistsForProject
  ),
  promises: ProjectHistoryHandler,
}
