#!/usr/bin/env ruby
PAGETITLE = "Nominate someone for ASF Member" # Wvisible:meeting
$LOAD_PATH.unshift '/srv/whimsy/lib'
require 'time'
require 'wunderbar'
require 'wunderbar/bootstrap'
require 'whimsy/asf'
require 'whimsy/asf/forms'
require 'whimsy/asf/member-files' # See for nomination file parsing
require 'whimsy/asf/wunderbar_updates'
require 'whimsy/asf/meeting-util'
require 'whimsy/asf/time-utils'
require 'mail'

MAILING_LIST = 'members@apache.org'

def emit_form(title, prev_data)
  _whimsy_panel(title, style: 'panel-success') do
    _form.form_horizontal method: 'post' do
      field = 'availid'
      _whimsy_forms_input(label: 'Nominee availid', name: field,
        value: prev_data[field], helptext: 'Enter the availid of the committer you are nominating for ASF Membership'
      )
      _whimsy_forms_input(label: 'Nominated by', name: 'nomby', readonly: true, value: $USER
      )
      _whimsy_forms_input(
        label: 'Seconded by', name: 'secby', helptext: 'Optional comma-separated list of seconds; ONLY if you have confirmed with the seconds directly'
      )
      field = 'statement'
      _whimsy_forms_input(label: 'Nomination Statement', name: field, rows: 10,
        value: prev_data[field], helptext: 'Explain why you believe this person would make a good ASF Member, and what projects/communities they work on at the ASF'
      )
      _whimsy_forms_submitwrap(
        noicon: true, label: 'submit', name: 'submit', value: 'submit', helptext: 'Checkin this nomination and send email to members@'
      )
    end
  end
end

# Validation as needed within the script
# Returns: 'OK' or a text message describing the problem
def validate_form(formdata: {})
  uid = formdata['availid'].downcase
  return "You MUST provide a nomination statement for Candidate #{uid}; blank was provided!" if formdata['statement'].empty?
  chk = ASF::Person[uid]&.asf_member?
  chk.nil? and return "Invalid availid supplied: (#{uid})\n\nStatement:\n#{formdata['statement']}"
  # Allow renomination of Emeritus
  pubname = ASF::Person[uid].public_name
  chk && !chk.to_s.start_with?('Emeritus') and return "Your nominee #{pubname} (#{uid}) is already an ASF member!"
  already = ASF::MemberFiles.member_nominees
  return "Candidate (#{uid}) has already been nominated by #{already[uid]['Nominated by']}" if already.include? uid
  return 'OK'
end

# Handle submission (checkout user's apacheid.json, write form data, checkin file)
# @return true if we think it succeeded; false in all other cases
def process_form(formdata: {}, wunderbar: {})
  _h3 "Transcript of update to nomination file #{ASF::MemberFiles::NOMINATED_MEMBERS}"
  entry = ASF::MemberFiles.make_member_nomination({
    availid: formdata['availid'].downcase,
    nomby: formdata['nomby'],
    secby: formdata['secby'],
    statement: formdata['statement']
  })

  environ = Struct.new(:user, :password).new($USER, $PASSWORD)
  ASF::MemberFiles.update_member_nominees(environ, wunderbar, [entry], "+= #{formdata['availid'].downcase}")
  return true
end

# Send email to members@ with this nomination's data
# Reports status to user in a _div
def send_nomination_mail(formdata: {})
  uid = formdata['availid'].downcase
  nomby = formdata['nomby']
  public_name = ASF::Person.new(uid).public_name
  secby = formdata.fetch('secby', nil)
  secby.nil? || secby.empty? ? nomseconds = '' : nomseconds = "Nomination seconded by: #{secby}"
  mail_body = <<-MAILBODY
This nomination for #{public_name} (#{uid}) as a New Member
Candidate has been added:

#{formdata['statement']}

#{nomseconds}

--
- #{ASF::Person[nomby].public_name}
  Email generated by Whimsy (#{File.basename(__FILE__)})

MAILBODY
# See check_membernoms.cgi which parses this in list archives
mailsubject = "[MEMBER NOMINATION] #{ASF::Person.new(uid).public_name} (#{uid})"

  ASF::Mail.configure
  mail = Mail.new do
    to MAILING_LIST
    bcc 'notifications@whimsical.apache.org'
    from "#{ASF::Person[nomby].public_name} <#{nomby}@apache.org>"
    subject mailsubject
    text_part do
      body mail_body
    end
  end
  begin
    mail.deliver!
  rescue StandardError => e
    _div.alert.alert_danger role: 'alert' do
      _p.strong "ERROR: email was NOT sent due to: #{e.message} #{e.backtrace[0]}"
      _p do
        _ "To: #{MAILING_LIST}"
        _br
        _ "Subject: #{mailsubject}"
        _br
        _ "#{mail_body}"
      end
    end
    return
  end
  _div.alert.alert_success role: 'alert' do
    _p "The following email was sent:"
    _p do
      _ "To: #{MAILING_LIST}"
      _br
      _ "Subject: #{mailsubject}"
      _br
      _ "#{mail_body}"
    end
  end
  return
end

# Produce HTML
_html do
  _body? do
    # Countdown until nominations for current meeting close
    latest_meeting_dir = ASF::MeetingUtil.latest_meeting_dir
    timelines = ASF::MeetingUtil.get_timeline(latest_meeting_dir)
    t_now = Time.now.to_i
    t_end = Time.parse(timelines['nominations_close_iso']).to_i
    nomclosed = t_now > t_end
    _whimsy_body(
      title: PAGETITLE,
      subtitle: 'About This Script',
      related: {
        'meeting.cgi' => 'Member Meeting FAQ and info',
        '/roster/committer/' => 'Lookup any committer availID',
        'memberless-pmcs.cgi' => 'PMCs with no/few ASF Members',
        'watch.cgi' => 'Watch list for potential Member candidates',
        'check_membernoms.cgi' => 'Cross-check existing Member nominations',
        ASF::SVN.svnpath!('Meetings') => 'Official Meeting Agenda Directory'
      },
      helpblock: -> {
        _b "For: #{timelines['meeting_type']} Meeting on: #{timelines['meeting_iso']}"
        _p do
          _ %Q{
            Use this form to nominate any Committer the new ASF Membership election.
            It automatically adds a properly formatted nomination to the #{ASF::MemberFiles::NOMINATED_MEMBERS} file,
            and will then 
          }
          _strong "send an email to the #{MAILING_LIST} list"
          _ ' from you with the nomination, '
          _a 'as is tradition.', href: 'https://lists.apache.org/list?members@apache.org:2023-2:%22MEMBER%20NOMINATION%22'
          _ ' This form only supports adding new nominations of existing committers; to add seconds or comments, please use SVN.  To nominate a non-committer, add them manually and use use n/a for the id. '
          _a 'Lookup committer availIDs', href: '/roster/committer/'
        end
      }
    ) do

      if nomclosed
        _h1 'Nominations are now closed!'
        _p 'Sorry, no further nominations will be accepted for ballots at this meeting.'
      else
        _h3 "Nominations close in #{ASFTime.secs2text(t_end - t_now)} at #{Time.at(t_end).utc} for Meeting: #{timelines['meeting_iso']}"
      end

      _div id: 'nomination-form' do
        if _.post?
          unless nomclosed
            submission = _whimsy_params2formdata(params)
            valid = validate_form(formdata: submission)
          end
          if nomclosed
            _div.alert.alert_warning role: 'alert' do
              _p "Nominations have closed"
            end
          elsif valid == 'OK'
            if process_form(formdata: submission, wunderbar: _)
              _div.alert.alert_success role: 'alert' do
                _p "Your nomination was submitted to svn; now sending email to #{MAILING_LIST}."
              end
              mailval = send_nomination_mail(formdata: submission)
              _pre mailval
            else
              _div.alert.alert_danger role: 'alert' do
                _p do
                  _span.strong "ERROR: Form data invalid in process_form(), update was NOT submitted!"
                  _br
                  _ "#{submission}"
                end
              end
            end
          else
            _div.alert.alert_danger role: 'alert' do
              _p do
                _span.strong "ERROR: Form data invalid in validate_form(), update was NOT submitted!"
                _br
                _p valid
              end
            end
          end
        else # if _.post?
          if nomclosed
            _p do
              _ 'Sorry, no further nominations will be accepted for ballots at this meeting.'
              _br
              _a 'See existing nominations.', href: '/members/check_membernoms.cgi'
            end
          else
            emit_form('Enter your New Member nomination', {})
          end
        end
      end
    end
  end
end
