const get = require('lodash/get')
const User = require('./User')

class Fragment {
  constructor({ fragment }) {
    this.fragment = fragment
  }

  set _fragment(newFragment) {
    this.fragment = newFragment
  }

  static setFragmentOwners(fragment = {}, author = {}) {
    const { owners = [] } = fragment
    if (author.isSubmitting) {
      const authorAlreadyOwner = owners.includes(author.id)
      if (!authorAlreadyOwner) {
        return [author.id, ...owners]
      }
    }
    return owners
  }

  async getFragmentData({ handlingEditor } = {}) {
    const { fragment: { metadata = {}, recommendations = [], id } } = this
    let heRecommendation

    if (handlingEditor) {
      heRecommendation = recommendations.find(
        rec => rec.userId === handlingEditor.id,
      )
    }

    let { title = '', abstract = '' } = metadata
    const { type } = metadata
    title = title.replace(/<(.|\n)*?>/g, '')
    abstract = abstract ? abstract.replace(/<(.|\n)*?>/g, '') : ''

    return {
      id,
      type,
      title,
      abstract,
      recommendations,
      heRecommendation,
    }
  }

  async addAuthor({ user, isSubmitting, isCorresponding }) {
    const { fragment } = this
    fragment.authors = fragment.authors || []
    const author = {
      id: user.id,
      firstName: user.firstName || '',
      lastName: user.lastName || '',
      email: user.email,
      title: user.title || '',
      affiliation: user.affiliation || '',
      isSubmitting,
      isCorresponding,
    }
    fragment.authors.push(author)
    fragment.owners = this.constructor.setFragmentOwners(fragment, author)
    await fragment.save()

    return author
  }

  async getAuthorData({ UserModel }) {
    const { fragment: { authors = [] } } = this
    const submittingAuthorData = authors.find(author => author.isSubmitting)

    try {
      const submittingAuthor = await UserModel.find(
        get(submittingAuthorData, 'id'),
      )

      const userHelper = new User({ UserModel })
      const activeAuthors = await userHelper.getActiveAuthors(authors)

      return {
        activeAuthors,
        submittingAuthor,
      }
    } catch (e) {
      throw e
    }
  }

  getInvitations({ isAccepted = true, role = 'reviewer', type }) {
    const { fragment: { invitations = [], recommendations = [] } } = this
    let filteredInvitations = isAccepted
      ? invitations.filter(
          inv =>
            inv.role === role &&
            inv.hasAnswer === true &&
            inv.isAccepted === true,
        )
      : invitations.filter(inv => inv.role === role && inv.hasAnswer === false)

    if (type === 'submitted') {
      filteredInvitations = filteredInvitations.filter(inv =>
        recommendations.find(
          rec =>
            rec.recommendationType === 'review' &&
            rec.submittedOn &&
            inv.userId === rec.userId,
        ),
      )
    }

    return filteredInvitations
  }

  getLatestHERequestToRevision() {
    const { fragment: { recommendations = [] } } = this
    return recommendations
      .filter(
        rec =>
          rec.recommendationType === 'editorRecommendation' &&
          (rec.recommendation === 'minor' || rec.recommendation === 'major'),
      )
      .sort((a, b) => b.createdOn - a.createdOn)[0]
  }

  async getReviewers({ UserModel, type }) {
    const isAccepted = type !== 'pending'
    const invitations = await this.getInvitations({ isAccepted, type })

    return (await Promise.all(
      invitations.map(inv => UserModel.find(inv.userId)),
    ))
      .filter(rev => rev.isActive)
      .filter(rev => get(rev, 'notifications.email.user'))
  }
}

module.exports = Fragment