const { union, omit } = require('lodash')

const {
  Team,
  services,
  Fragment,
  Collection,
  authsome: authsomeHelper,
} = require('pubsweet-component-helper-service')

const notifications = require('./notifications/notifications')

module.exports = models => async (req, res) => {
  const { collectionId, fragmentId } = req.params
  let collection, fragment

  try {
    collection = await models.Collection.find(collectionId)
    if (!collection.fragments.includes(fragmentId))
      return res.status(400).json({
        error: `Collection and fragment do not match.`,
      })

    fragment = await models.Fragment.find(fragmentId)
    if (!fragment.revision) {
      return res.status(400).json({
        error: 'No revision has been found.',
      })
    }

    const authsome = authsomeHelper.getAuthsome(models)
    const target = {
      fragment,
      path: req.route.path,
    }
    const canPatch = await authsome.can(req.user, 'PATCH', target)
    if (!canPatch)
      return res.status(403).json({
        error: 'Unauthorized.',
      })

    const collectionHelper = new Collection({ collection })
    const fragmentHelper = new Fragment({ fragment })
    const heRecommendation = fragmentHelper.getLatestHERequestToRevision()
    if (!heRecommendation) {
      return res.status(400).json({
        error: 'No Handling Editor request to revision has been found.',
      })
    }

    const newFragmentBody = {
      ...omit(fragment, ['revision', 'recommendations', 'id']),
      ...fragment.revision,
      invitations: fragmentHelper.getInvitations({
        isAccepted: true,
        type: 'submitted',
      }),
      version: fragment.version + 1,
      created: new Date(),
    }

    let newFragment = new models.Fragment(newFragmentBody)
    newFragment = await newFragment.save()
    const teamHelper = new Team({
      TeamModel: models.Team,
      collectionId,
      fragmentId: newFragment.id,
    })
    delete fragment.revision
    fragment.save()

    if (heRecommendation.recommendation === 'major') {
      const reviewerIds = newFragment.invitations.map(inv => inv.userId)

      teamHelper.createTeam({
        role: 'reviewer',
        members: reviewerIds,
        objectType: 'fragment',
      })
    } else {
      delete newFragment.invitations
      await newFragment.save()
    }

    const authorIds = newFragment.authors.map(auth => {
      const { id } = auth
      return id
    })

    let authorsTeam = await teamHelper.getTeam({
      role: 'author',
      objectType: 'fragment',
    })

    if (!authorsTeam) {
      authorsTeam = await teamHelper.createTeam({
        role: 'author',
        members: authorIds,
        objectType: 'fragment',
      })
    } else {
      authorsTeam.members = union(authorsTeam.members, authorIds)
      await authorsTeam.save()
    }

    await collectionHelper.updateStatusByRecommendation({
      recommendation: heRecommendation.recommendation,
    })

    newFragment.submitted = Date.now()
    newFragment = await newFragment.save()
    collection.fragments.push(newFragment.id)
    collection.save()

    notifications.sendHandlingEditorEmail({
      baseUrl: services.getBaseUrl(req),
      fragment: newFragment,
      UserModel: models.User,
      collection,
    })

    if (heRecommendation.recommendation === 'major') {
      notifications.sendReviewersEmail({
        baseUrl: services.getBaseUrl(req),
        fragment: newFragment,
        UserModel: models.User,
        collection,
        previousVersion: fragment,
      })
    }

    return res.status(200).json(newFragment)
  } catch (e) {
    const notFoundError = await services.handleNotFoundError(e, 'Item')
    return res.status(notFoundError.status).json({
      error: notFoundError.message,
    })
  }
}