import _ from 'lodash'
import App from '../../../base'
App.controller('ShareProjectModalController', function (
  $scope,
  $modalInstance,
  $timeout,
  projectMembers,
  projectInvites,
  $modal,
  $http,
  ide,
  validateCaptcha,
  validateCaptchaV3,
  settings,
  // eslint-disable-next-line camelcase
  eventTracking
) {
  $scope.inputs = {
    privileges: 'readAndWrite',
    contacts: []
  }
  $scope.state = {
    error: null,
    errorReason: null,
    inflight: false,
    startedFreeTrial: false,
    invites: []
  }

  $modalInstance.opened.then(() =>
    $timeout(() => $scope.$broadcast('open'), 200)
  )

  const INFINITE_COLLABORATORS = -1

  $scope.refreshCanAddCollaborators = function () {
    const allowedNoOfMembers = $scope.project.features.collaborators
    $scope.canAddCollaborators =
      $scope.project.members.length + $scope.project.invites.length <
        allowedNoOfMembers || allowedNoOfMembers === INFINITE_COLLABORATORS
  }
  $scope.refreshCanAddCollaborators()

  $scope.$watch('canAddCollaborators', function () {
    if (!$scope.canAddCollaborators) {
      eventTracking.send(
        'subscription-funnel',
        'editor-click-feature',
        'projectMembers'
      )
    }
  })

  $scope.$watch(
    '(project.members.length + project.invites.length)',
    _noOfMembers => $scope.refreshCanAddCollaborators()
  )

  $scope.autocompleteContacts = []
  if ($scope.isRestrictedTokenMember) {
    // Restricted token members are users who join via a read-only link.
    // They will not be able to invite any users, so skip the lookup of
    //  their contacts. This request would result in a 403 for anonymous
    //  users, which in turn would redirect them to the /login.
  } else {
    $http.get('/user/contacts').then(processContactsResponse)
  }

  function processContactsResponse(response) {
    const { data } = response
    $scope.autocompleteContacts = data.contacts || []
    for (let contact of $scope.autocompleteContacts) {
      if (contact.type === 'user') {
        if (
          contact.first_name === contact.email.split('@')[0] &&
          !contact.last_name
        ) {
          // User has not set their proper name so use email as canonical display property
          contact.display = contact.email
        } else {
          contact.name = `${contact.first_name} ${contact.last_name}`
          contact.display = `${contact.name} <${contact.email}>`
        }
      } else {
        // Must be a group
        contact.display = contact.name
      }
    }
  }

  const getCurrentMemberEmails = () =>
    ($scope.project.members || []).map(u => u.email)

  const getCurrentInviteEmails = () =>
    ($scope.project.invites || []).map(u => u.email)

  $scope.filterAutocompleteUsers = function ($query) {
    const currentMemberEmails = getCurrentMemberEmails()
    return $scope.autocompleteContacts.filter(function (contact) {
      if (
        contact.email != null &&
        currentMemberEmails.includes(contact.email)
      ) {
        return false
      }
      for (let text of [contact.name, contact.email]) {
        if (
          text != null &&
          text.toLowerCase().indexOf($query.toLowerCase()) > -1
        ) {
          return true
        }
      }
      return false
    })
  }

  $scope.addMembers = function () {
    const addMembers = function () {
      if ($scope.inputs.contacts.length === 0) {
        return
      }

      const members = $scope.inputs.contacts
      $scope.inputs.contacts = []
      $scope.clearError()
      $scope.state.inflight = true

      if ($scope.project.invites == null) {
        $scope.project.invites = []
      }

      const currentMemberEmails = getCurrentMemberEmails()
      const currentInviteEmails = getCurrentInviteEmails()
      addNextMember()

      function addNextMember() {
        let email
        if (members.length === 0 || !$scope.canAddCollaborators) {
          $scope.state.inflight = false
          $scope.$apply()
          return
        }

        const member = members.shift()
        if (member.type === 'user') {
          email = member.email
        } else {
          // Not an auto-complete object, so email == display
          email = member.display
        }
        email = email.toLowerCase()

        if (currentMemberEmails.includes(email)) {
          // Skip this existing member
          return addNextMember()
        }
        // do v3 captcha to collect data only
        validateCaptchaV3('invite')
        // do v2 captcha
        const ExposedSettings = window.ExposedSettings
        validateCaptcha(function (response) {
          $scope.grecaptchaResponse = response
          const invites = $scope.project.invites || []
          const invite = _.find(invites, invite => invite.email === email)
          let request
          if (currentInviteEmails.includes(email) && invite) {
            request = projectInvites.resendInvite(invite._id)
          } else {
            request = projectInvites.sendInvite(
              email,
              $scope.inputs.privileges,
              $scope.grecaptchaResponse
            )
          }

          request
            .then(function (response) {
              const { data } = response
              if (data.error) {
                $scope.setError(data.error)
                $scope.state.inflight = false
              } else {
                if (data.invite) {
                  const { invite } = data
                  $scope.project.invites.push(invite)
                } else {
                  const users =
                    data.users != null
                      ? data.users
                      : data.user != null
                      ? [data.user]
                      : []
                  $scope.project.members.push(...users)
                }
              }

              setTimeout(
                () =>
                  // Give $scope a chance to update $scope.canAddCollaborators
                  // with new collaborator information.
                  addNextMember(),

                0
              )
            })
            .catch(function (httpResponse) {
              const { data } = httpResponse
              $scope.state.inflight = false
              $scope.setError(data.errorReason)
            })
        }, ExposedSettings.recaptchaDisabled.invite)
      }
    }

    $timeout(addMembers, 50) // Give email list a chance to update
  }

  $scope.removeMember = function (member) {
    $scope.monitorRequest(
      projectMembers.removeMember(member).then(function () {
        const index = $scope.project.members.indexOf(member)
        if (index === -1) {
          return
        }
        $scope.project.members.splice(index, 1)
      })
    )
  }

  $scope.revokeInvite = function (invite) {
    $scope.monitorRequest(
      projectInvites.revokeInvite(invite._id).then(function () {
        const index = $scope.project.invites.indexOf(invite)
        if (index === -1) {
          return
        }
        $scope.project.invites.splice(index, 1)
      })
    )
  }

  $scope.resendInvite = function (invite, event) {
    $scope.monitorRequest(
      projectInvites
        .resendInvite(invite._id)
        .then(function () {
          event.target.blur()
        })
        .catch(function () {
          event.target.blur()
        })
    )
  }

  $scope.makeTokenBased = function () {
    $scope.project.publicAccesLevel = 'tokenBased'
    settings.saveProjectAdminSettings({ publicAccessLevel: 'tokenBased' })
    eventTracking.sendMB('project-make-token-based')
  }

  $scope.makePrivate = function () {
    $scope.project.publicAccesLevel = 'private'
    settings.saveProjectAdminSettings({ publicAccessLevel: 'private' })
  }

  $scope.$watch('project.tokens.readAndWrite', function (token) {
    if (token != null) {
      $scope.readAndWriteTokenLink = `${location.origin}/${token}`
    } else {
      $scope.readAndWriteTokenLink = null
    }
  })

  $scope.$watch('project.tokens.readOnly', function (token) {
    if (token != null) {
      $scope.readOnlyTokenLink = `${location.origin}/read/${token}`
    } else {
      $scope.readOnlyTokenLink = null
    }
  })

  $scope.done = () => $modalInstance.close()

  $scope.cancel = () => $modalInstance.dismiss()

  $scope.monitorRequest = function monitorRequest(request) {
    $scope.clearError()
    $scope.state.inflight = true
    return request
      .then(() => {
        $scope.state.inflight = false
        $scope.clearError()
      })
      .catch(err => {
        $scope.state.inflight = false
        $scope.setError(err.data && err.data.error)
      })
  }

  $scope.clearError = function clearError() {
    $scope.state.error = false
  }

  $scope.setError = function setError(reason) {
    $scope.state.error = true
    $scope.state.errorReason = reason
  }
})
