import { get, has, last, chain } from 'lodash'
import { selectCurrentUser } from 'xpub-selectors'

export const isHEToManuscript = (state, collectionId) => {
  const { id = '', isAccepted = false } = chain(state)
    .get('collections', [])
    .find(c => c.id === collectionId)
    .get('handlingEditor', '')
    .value()
  return isAccepted && id === get(state, 'currentUser.user.id')
}

export const currentUserIs = ({ currentUser: { user } }, role) => {
  const isAdmin = get(user, 'admin')
  const isEic = get(user, 'editorInChief')
  const isHe = get(user, 'handlingEditor')
  switch (role) {
    case 'isHE':
      return isHe
    case 'staff':
      return isAdmin || isEic || isHe
    case 'isEiC':
      return isEic
    case 'isAdmin':
      return isAdmin
    case 'adminEiC':
      return isAdmin || isEic
    default:
      return false
  }
}

const canInviteReviewersStatuses = [
  'heAssigned',
  'reviewersInvited',
  'underReview',
  'reviewCompleted',
]
export const canInviteReviewers = (state, collection) => {
  if (!canInviteReviewersStatuses.includes(get(collection, 'status', 'draft')))
    return false

  const user = selectCurrentUser(state)
  const isAdmin = currentUserIs(state, 'isAdmin')
  const { isAccepted, id: heId } = get(collection, 'handlingEditor', {})

  return isAccepted && (user.id === heId || isAdmin)
}

const cannotViewReviewersDetails = [
  'draft',
  'technicalChecks',
  'submitted',
  'heInvited',
]

export const canViewReviewersDetails = (state, collection = {}) => {
  const isHeAssigned = !!get(collection, 'handlingEditor', false)
  if (
    cannotViewReviewersDetails.includes(get(collection, 'status', 'draft')) ||
    !isHeAssigned
  ) {
    return false
  }
  return canViewReports(state, collection.id)
}

const cannotAuthorViewEditorialCommentsStatuses = [
  'draft',
  'technicalChecks',
  'submitted',
  'heInvited',
  'heAssigned',
  'reviewersInvited',
]

export const canAuthorViewEditorialComments = (
  state,
  collection = {},
  fragmentId,
) => {
  const isAuthor = currentUserIsAuthor(state, fragmentId)
  return (
    isAuthor &&
    !cannotAuthorViewEditorialCommentsStatuses.includes(
      get(collection, 'status', 'draft'),
    )
  )
}

const canHeViewEditorialCommentsStatuses = [
  'revisionRequested',
  'rejected',
  'accepted',
  'inQA',
  'pendingApproval',
  'reviewCompleted',
]
export const canHeViewEditorialComments = (state, collection = {}) => {
  const isHE = isHEToManuscript(state, collection.id)
  const status = get(collection, 'status', 'draft')
  return isHE && canHeViewEditorialCommentsStatuses.includes(status)
}

const canEICViewEditorialCommentsStatuses = [
  'rejected',
  'accepted',
  'inQA',
  'pendingApproval',
  'reviewCompleted',
]
export const canEICViewEditorialComments = (state, collection = {}) => {
  const isEIC = currentUserIs(state, 'adminEiC')
  const status = get(collection, 'status', 'draft')
  return isEIC && canEICViewEditorialCommentsStatuses.includes(status)
}

export const canViewEditorialComments = (
  state,
  collection = {},
  fragmentId,
) => {
  const editorialRecommentations = getFragmentEditorialComments(
    state,
    fragmentId,
  )
  return (
    (canHeViewEditorialComments(state, collection) ||
      canEICViewEditorialComments(state, collection) ||
      canAuthorViewEditorialComments(state, collection, fragmentId)) &&
    editorialRecommentations.length > 0
  )
}

export const getUserToken = ({ currentUser }) =>
  get(currentUser, 'user.token', '')

export const getHERecommendation = (state, collectionId, fragmentId) => {
  const heId = chain(state)
    .get('collections', [])
    .find(c => c.id === collectionId)
    .get('handlingEditor.id', '')
    .value()

  return (
    chain(state)
      .get(`fragments.${fragmentId}.recommendations`, [])
      .find(r => r.rec === 'editorRecommendation' && r.userId === heId)
      .value() || {}
  )
}

const canMakeDecisionStatuses = ['submitted', 'pendingApproval']
export const canMakeDecision = (state, collection, fragment = {}) => {
  if (fragment.id !== last(get(collection, 'fragments', []))) return false
  const status = get(collection, 'status', 'draft')

  const isEIC = currentUserIs(state, 'adminEiC')
  return isEIC && canMakeDecisionStatuses.includes(status)
}

const canEditManuscriptStatuses = ['draft', 'technicalChecks', 'inQA']
export const canEditManuscript = (state, collection, fragment = {}) => {
  const isAdmin = currentUserIs(state, 'isAdmin')
  if (!isAdmin || fragment.id !== last(get(collection, 'fragments', [])))
    return false
  const status = get(collection, 'status', 'draft')

  return canEditManuscriptStatuses.includes(status)
}

const canOverrideTechnicalChecksStatuses = ['technicalChecks', 'inQA']
export const canOverrideTechnicalChecks = (state, collection) => {
  const isAdmin = currentUserIs(state, 'isAdmin')
  if (!isAdmin) return false
  const status = get(collection, 'status', 'draft')

  return canOverrideTechnicalChecksStatuses.includes(status)
}

export const canViewReports = (state, collectionId) => {
  const isHE = isHEToManuscript(state, collectionId)
  const isEiC = currentUserIs(state, 'adminEiC')
  return isHE || isEiC
}

export const canMakeRevision = (state, collection, fragment) => {
  const currentUserId = get(state, 'currentUser.user.id')
  return (
    get(fragment, 'revision') &&
    collection.status === 'revisionRequested' &&
    fragment.owners.map(o => o.id).includes(currentUserId)
  )
}

export const currentUserIsAuthor = (state, id) => {
  const permissions = getUserPermissions(state)

  return permissions
    .filter(f => f.role === 'author')
    .map(p => p.objectId)
    .includes(id)
}

export const getUserPermissions = ({ currentUser }) =>
  get(currentUser, 'user.teams', []).map(t => ({
    objectId: t.object.id,
    objectType: t.object.type,
    role: t.teamType.permissions,
  }))

export const userNotConfirmed = ({ currentUser }) =>
  get(currentUser, 'isAuthenticated') &&
  !currentUserIs({ currentUser }, 'staff') &&
  !get(currentUser, 'user.isConfirmed')

export const pendingReviewerInvitation = (state, fragmentId) =>
  chain(state)
    .get(`fragments.${fragmentId}.invitations`, [])
    .find(
      inv =>
        inv.userId === get(state, 'currentUser.user.id', '') &&
        !inv.hasAnswer &&
        inv.role === 'reviewer',
    )
    .value()

export const currentUserIsReviewer = (state, fragmentId) => {
  const currentUser = selectCurrentUser(state)
  const invitations = get(state, `fragments.${fragmentId}.invitations`, [])
  return !!invitations.find(
    i =>
      i.userId === currentUser.id &&
      i.role === 'reviewer' &&
      i.hasAnswer &&
      i.isAccepted,
  )
}

export const getAdminUsers = state =>
  chain(state)
    .get('users.users')
    .map(u => {
      let sortValue = -1
      if (u.isActive) sortValue = 1
      if (!u.isConfirmed) sortValue = 0
      return {
        user: u,
        sortValue,
      }
    })
    .sortBy('sortValue')
    .map(s => s.user)
    .reverse()
    .value()

export const pendingHEInvitation = (state, collectionId) =>
  chain(state)
    .get('collections', [])
    .find(c => c.id === collectionId)
    .get('invitations', [])
    .find(
      i =>
        i.userId === get(state, 'currentUser.user.id', '') &&
        i.role === 'handlingEditor' &&
        !i.hasAnswer,
    )
    .value()

const parseInvitedHE = (handlingEditor, state, collectionId) =>
  handlingEditor && {
    ...handlingEditor,
    name: pendingHEInvitation(state, collectionId)
      ? 'Invited'
      : handlingEditor.name,
  }

const hideCustomIdStatuses = ['draft', 'technicalChecks']

export const parseCollectionDetails = (state, collection = {}) => ({
  ...collection,
  customId:
    !hideCustomIdStatuses.includes(get(collection, 'status', 'draft')) &&
    collection.customId,
  handlingEditor: parseInvitedHE(
    collection.handlingEditor,
    state,
    collection.id,
  ),
})

export const newestFirstParseDashboard = (state = {}) =>
  chain(state.collections)
    .orderBy(['created'], ['desc'])
    .map(item => parseCollectionDetails(state, item))
    .value()

export const getInvitationsWithReviewersForFragment = (state, fragmentId) =>
  chain(state)
    .get(`fragments.${fragmentId}.invitations`, [])
    .filter(invitation => invitation.role === 'reviewer')
    .map(invitation => ({
      ...invitation,
      person: get(state, 'users.users', []).find(
        reviewer => reviewer.id === invitation.userId,
      ),
    }))
    .value()

export const canMakeHERecommendation = (state, { collection, statuses }) => {
  const validHE = isHEToManuscript(state, get(collection, 'id', ''))
  const statusImportance = get(
    statuses,
    `${get(collection, 'status', 'draft')}.importance`,
    1,
  )

  return statusImportance > 1 && statusImportance < 9 && validHE
}

// #region Editorial and reviewer recommendations
export const getFragmentRecommendations = (state, fragmentId) =>
  get(state, `fragments.${fragmentId}.recommendations`, [])

export const getFragmentReviewerRecommendations = (state, fragmentId) =>
  getFragmentRecommendations(state, fragmentId).filter(
    r => r.recommendationType === 'review',
  )
const getFragmentEditorialComments = (state, fragmentId) =>
  getFragmentRecommendations(state, fragmentId).filter(
    r => r.recommendationType === 'editorRecommendation',
  )

const getOwnRecommendations = (state, fragmentId) =>
  chain(state)
    .get(`fragments.${fragmentId}.recommendations`, [])
    .filter(r => r.userId === get(state, 'currentUser.user.id', ''))
    .value()

export const getOwnPendingRecommendation = (state, fragmentId) =>
  chain(getOwnRecommendations(state, fragmentId))
    .find(
      r =>
        r.userId === get(state, 'currentUser.user.id', '') &&
        !has(r, 'submittedOn'),
    )
    .value()

export const getOwnSubmittedRecommendation = (state, fragmentId) =>
  chain(getOwnRecommendations(state, fragmentId))
    .find(
      r =>
        r.userId === get(state, 'currentUser.user.id', '') &&
        has(r, 'submittedOn'),
    )
    .value()

const canMakeRecommendationStatuses = [
  'heAssigned',
  'underReview',
  'reviewCompleted',
]
export const canMakeRecommendation = (state, collection, fragment = {}) => {
  if (fragment.id !== last(get(collection, 'fragments', []))) return false
  const isHE = isHEToManuscript(state, get(collection, 'id', ''))
  const status = get(collection, 'status', 'draft')
  return isHE && canMakeRecommendationStatuses.includes(status)
}
// #endregion