class Person < Vue
  def initialize
    @committer = {}
    @response = nil
  end

  def render
    # usage information for authenticated users (owner, secretary, etc.)
    if @auth
      _div.alert.alert_success 'Double click on a field in this color to edit.'
    end

    _h2 "#{@committer.id}@apache.org"

    # Name
    _PersonName person: self, edit: @edit

    _div.row do
      _div.name 'LDAP Create Date'
      _div.value do
        _ @committer.createTimestamp
      end
    end

    # Personal URL
    if @committer.urls || @auth
      @committer.urls ||= []
      _PersonUrls person: self, edit: @edit
    end

    # PMCs
    noPMCsub = false
    pmcs = @committer.pmcs.slice() # Take copy to avoid affecting original
    # allow for non-PMC chairs
    @committer.chairOf.each do |pmcchair|
      pmcs << pmcchair unless pmcs.include? pmcchair
    end
    unless pmcs.empty?
      _div.row do
        _div.name 'PMCs'
        _div.value do
          _ul pmcs do |pmc|
            _li {
              _a pmc, href: "committee/#{pmc}"
              if @committer.privateNosub
                if @committer.privateNosub.include? pmc
                  noPMCsub = true
                  _b ' (*)'
                end
              end
              if @committer.chairOf.include? pmc
                _ ' (chair)'
              end
              unless @committer.pmcs.include?(pmc)
                _b ' (not on PMC)'
              end
              unless @committer.committees.include?(pmc)
                _b ' (not in LDAP committee group)'
              end
              unless @committer.committer.include?(pmc)
                _b ' (not in LDAP committer group)'
              end
            }
          end
          if noPMCsub
                  _br
            _p {
              _ '(*) could not find a subscription to the private@ mailing list for this PMC'
              _br
              _ 'Perhaps the subscription address is not listed in the LDAP record'
            }
          end
        end
      end
    end

    # Committees
    missingPMCs = false
    committees = @committer.committees
    unless committees.empty?
      _div.row do
        _div.name 'Committees'
        _div.value do
          noPMCsub = false
          _ul committees do |pmc|
            next if  @committer.pmcs.include? pmc
            missingPMCs = true
            _li {
              _a pmc, href: "committee/#{pmc}"
              if @committer.chairOf.include? pmc
                _ ' (chair)'
              end
            }
          end
          if missingPMCs
            _ 'In LDAP committee group, but not on the corresponding PMC'
          else
            _ '(excludes PMCs listed above)'
          end
        end
      end
    end

    # Committer
    commit_list = @committer.committer
    unless commit_list.all? {|pmc| committees.include? pmc}
      _div.row do
        _div.name 'Committer'
        _div.value do
          _ul commit_list do |pmc|
            next if committees.include? pmc
            _li {_a pmc, href: "committee/#{pmc}"}
          end
        end
      end
    end

    # Groups
    unless @committer.groups.empty?
      _div.row do
        _div.name 'Groups'
        _div.value do
          _ul @committer.groups do |group|
            next if group == 'apldap'

            if group == 'committers'
              _li {_a group, href: 'committer/'}
            elsif group == 'member'
              _li {_a group, href: 'members'}
            else
              _li {_a group, href: "group/#{group}"}
            end
            if @committer.chairOf.length > 0 and not @committer.groups.include? 'pmc-chairs'
              _ '[Missing: pmc-chairs]'
            end
          end
        end
      end
    end

    # Podlings
    unless @committer.podlings.empty?
      _div.row do
        _div.name 'Podlings'
        _div.value do
          _ul @committer.podlings do |podlings|
            _li {_a podlings, href: "ppmc/#{podlings}"}
          end
        end
      end
    end

    # Non-PMCs
    nonpmcs = @committer.nonpmcs
    unless nonpmcs.empty?
      _div.row do
        _div.name 'non-PMCs'
        _div.value do
          _ul nonpmcs do |nonpmc|
            _li {
              _a nonpmc, href: "nonpmc/#{nonpmc}"
              if @committer.nonPMCchairOf.include? nonpmc
                _ ' (chair)'
              end
            }
          end
        end
      end
    end

    if @auth # deprecate using outlook.com
      _div.row do
        _div.name 'Email provider issues'
        _div.value do
          _ 'Some providers are known to block our emails as SPAM.'
          _br
          _ 'Please see the following for details: '
          _a 'email provider issues', href: '../committers/emailissues', target: '_blank'
          _ ' (opens in new page)'
        end
      end
    end

    # Email addresses
    # always present
    _PersonEmailForwards person: self, edit: @edit

    # always present (even if an empty array)
    _PersonEmailAlt person: self, edit: @edit

    if @committer.email_other
      _PersonEmailOther person: self # not editable
    end

    # Moderates
    if @committer.moderates and @committer.moderates.keys().length > 0
      _div.row do
        _div.name 'Moderates'
        _div.value do
          _ul @committer.moderates.keys() do |list_name|
            _li do
              _a list_name, href: 'https://lists.apache.org/list.html?' +
                list_name
              _span ' as '
              _span @committer.moderates[list_name].join(', ')
            end
          end
          _ "(last checked #{@committer.modtime})"
        end
      end
    end

    # subscriptions
    if @committer.subscriptions
      _div.row do
        _div.name 'Subscriptions'
        _div.value do
          _ul @committer.subscriptions do |list_email|
            _li do
              _a list_email[0],
                href: 'https://lists.apache.org/list.html?' + list_email[0]
              _span ' as '
              _span list_email[1]
            end
          end
          _ "(last checked #{@committer.subtime})"
        end
      end
    end

    # digests
    if @committer.digests
      _div.row do
        _div.name 'Digest Subscriptions'
        _div.value do
          _ul @committer.digests do |list_email|
            _li do
              _a list_email[0],
                href: 'https://lists.apache.org/list.html?' + list_email[0]
              _span ' as '
              _span list_email[1]
            end
          end
          _ "(last checked #{@committer.digtime})"
        end
      end
    end

    # PGP keys
    if @committer.pgp || @auth
      @committer.pgp ||= []
      _PersonPgpKeys person: self, edit: @edit
    end

    # hosts
    _div.row do
      _div.name 'Host Access'
      _div.value do
        # pre avoids wrapping on hyphens and reduces number of lines on the page
        _pre @committer.host.join(' ')
      end
    end

    if @committer.inactive
      _div.row do
        _div.name 'Inactive (cannot login)'
        _div.value @committer.inactive
      end
    end

    # SSH keys
    if @committer.ssh || @auth
      @committer.ssh ||= []
      _PersonSshKeys person: self, edit: @edit
    end

    # GitHub username
    if @committer.githubUsername || @auth
      @committer.githubUsername ||= []
      _PersonGitHub person: self, edit: @edit
    end

    if @committer.member
      _PersonMemberStatus person: self, edit: @edit

      # Members.txt
      if @committer.member.info
        _PersonMemberText person: self, edit: @edit
      end

      if @committer.member.nomination
        _div.row do
          _div.name 'Nomination'
          _div.value {_pre @committer.member.nomination}
        end
      end

    end

    # Forms on file (only present if env.user is a member)
    if @committer.forms
      _PersonForms person: self
    end

    # SpamAssassin score
    _PersonSascore person: self, edit: @edit

    # modal dialog for dry run results and errors
    _div.modal.fade.wide_form tabindex: -1 do
      _div.modal_dialog do
        _div.modal_content do
          _div.modal_header do
            _button.close 'x', data_dismiss: 'modal'
            _h4 @response_title
          end
          _div.modal_body do
            _textarea value: @response, readonly: true
          end
          _div.modal_footer do
            _button.btn.btn_default 'Close', data_dismiss: 'modal'
          end
        end
      end
    end
  end

  # initialize committer, determine if user is authorized to make
  # changes, map Vue model to React model
  def created()
    @committer = @@committer
    @auth = (@@auth.id == @@committer.id or @@auth.secretary or @@auth.root)

    # map Vue model to React model
    self.state = self['$data']
    self.props = self['$props']
  end

  # on initial display, look for add editable rows, highlight them,
  # and watch for double clicks on them
  def mounted()
    return unless @auth

    Array(document.querySelectorAll('div.row[data-edit]')).each do |div|
      div.addEventListener('dblclick', self.dblclick)
      div.querySelector('div.name').classList.add 'bg-success'
    end
  end

  # when a double click occurs, toggle the associated state
  def dblclick(event)
    row = event.currentTarget

    if row.dataset.edit == @edit
      @edit = nil
    else
      @edit = row.dataset.edit
    end

    window.getSelection().removeAllRanges()
  end

  # after update, register event listeners on forms
  def updated()
    Array(document.querySelectorAll('div[data-edit]')).each do |tr|
      form = tr.querySelector('form')
      if form
        form.setAttribute 'data-action', tr.getAttribute('data-edit')
        jQuery('input[type=submit],button', form).click(self.submit)
      end
    end
  end

  # submit form using AJAX
  def submit(event)
    event.preventDefault()
    form = jQuery(event.currentTarget).closest('form')
    target = event.target

    # if event has the skip submit attribute, return immediately
    # (used for fast return from validation)
    return if target.getAttribute('data-skip-submit')

    # if (cancel) button is pressed, don't submit but remove @edit form
    cancel_submit = target.getAttribute('data-cancel-submit')

    if cancel_submit
      # remove the edit buttons and return
      @edit = nil
      return
    end

    # serialize form
    formData = form.serializeArray();

    # add button if it has a value
    if target and target.getAttribute('name') and target.getAttribute('value')
      formData.push name: target.getAttribute('name'),
        value: target.getAttribute('value')
    end

    # indicate dryrun is requested if option or control key is down
    if event.altKey or event.ctrlKey
      formData.unshift name: 'dryrun', value: true
    end

    # issue request
    jQuery.ajax(
      method: (form[0].method || 'GET').upcase(),
      url: document.location.href + '/' + form[0].getAttribute('data-action'),
      data: formData,
      dataType: 'json',

      success: ->(response) {
        @committer = response.committer if response.committer

        # turn off edit mode on this field
        row = form.closest('.row')[0]
        @edit = nil if row and row.dataset.edit == @edit
      },

      error: ->(response) {
        json = response.responseJSON
        if json.exception
          @response_title = json.exception
          @response = JSON.stringify(json, nil, 2)
          jQuery('div.modal').modal('show')
        else
          alert response.statusText
        end
      },

      complete: ->(response) do
        json = response.responseJSON
        # show results of dryrun
        if formData[0] and formData[0].name == 'dryrun'
          @response_title = 'Dry run results'
          @response = JSON.stringify(json, nil, 2)
          jQuery('div.modal').modal('show')
        end

        if json.error
          @response_title = 'Error occurred'
          @response = JSON.stringify(json, nil, 2)
          jQuery('div.modal').modal('show')
        elsif json.warn
          alert json.warn
        end

        # re-enable form for later reuse
        jQuery('input, button', form).prop('disabled', false)
      end
    )

    # disable input
    jQuery('input, button', form).prop('disabled', true)
  end
end
