#!/usr/bin/env ruby

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#--------------------------------------------------------
#
# Script to create _data/projects YAML file for one or more project ids
#
# Usage:
# ruby retire.rb <list of project ids>
# e.g.
# ruby retire.rb gora mxnet
# This will create/update _data/projects/pid.yaml
# Review this and commit

# TODO:
# - does not check for Bugzilla issues
# - does not check for GitHub issues
# - Jira: juddi - does not find scout (is there an alias documented somewhere?)
# - Cwiki: did not find ODE2
# - aliases: does not check for previous names

# Input:
# - https://whimsy.apache.org/public/committee-retired.json
# - https://lists.apache.org/api/preferences.lua
# - https://cwiki.apache.org/confluence/rest/api/space/
# - https://issues.apache.org/jira/rest/api/2/project
# - https://svn.apache.org/repos/asf/
# - https://gitbox.apache.org/repositories.json
# - https://svn.apache.org/repos/asf/infrastructure/site/trunk/content/foundation/records/minutes (temporary)
#
# Output:
# _data/projects/pid.yaml

require 'yaml'
require 'net/http'
require 'uri'
require 'open3'

# Sources
CTTEE_RETIRED = 'https://whimsy.apache.org/public/committee-retired.json'
CWIKI_INFO = 'https://cwiki.apache.org/confluence/rest/api/space/?type=global&limit=1000'
# Note: Two Wikis are lower-case: labs, usergrid. Upper case does seem to be equivalent for display.
JIRA = 'https://issues.apache.org/jira/rest/api/2/project'
SVNURL = 'https://svn.apache.org/repos/asf/'
GITREPOS = 'https://gitbox.apache.org/repositories.json'
LISTSAO = 'https://lists.apache.org/api/preferences.lua'
MINUTES = 'https://svn.apache.org/repos/asf/infrastructure/site/trunk/content/foundation/records/minutes/'

def get_url(url)
  uri = URI.parse(url)
  Net::HTTP.start(uri.host, uri.port,
    open_timeout: 5, read_timeout: 5, ssl_timeout: 5,
    use_ssl: uri.scheme == 'https') do |http|
    return http.request Net::HTTP::Get.new uri.request_uri
  end
end

def get_json(url, key=nil)
  begin
    response = get_url(url)
    json = YAML.safe_load(response.body)
    if key
      return json[key]
    else
      return json
    end
  rescue Net::OpenTimeout => to
    puts to
    return nil
  end
end

def has_svn(pid)
  cmd = ['svn', 'ls', SVNURL + pid]
  _out, _err, status = Open3.capture3(*cmd)
  status.success?
end

# TODO: replace with full date from committee-retired when implemented
def get_board_date(yyyymm)
  cmd = ['svn', 'ls', MINUTES+yyyymm[0,4]]
  out, err, status = Open3.capture3(*cmd)
  if status.success?
    m = out.split("\n").select {|l| l.include? yyyymm.sub('-','_')}.map {|d| d[14,10].gsub('_', '-')}
    return m # e.g. 2011-11 has two dates
  else
    p err
    return yyyymm
  end
end


# "key": "GMOxDOC21es",
# "name": " Apache Geronimo v2.1 - ES  ",
def find_wikis(pid)
  names = []
  WIKIS.each do |a|
    key = a['key']
    names << key if key == pid or key.start_with?(pid) or a['name'].downcase =~ /\b#{pid}\b/
  end
  names.sort
end

# Allow for Apache prefix and (Retired) suffixes etc.
# returns first word, downcased
# TODO: what about subnames?
def canon_name(name)
  name.downcase.sub('apache','').gsub('(retired)', '').sub('(old)', '').strip.split.first
end

def get_jiras(pid)
  jiras = []
  JIRAS.each do |project|
    key = project['key']
    if pid == key.downcase
      jiras << key
    elsif pid == canon_name(project['name']) # Allow
      jiras << key
    else
      cat = project['projectCategory']
      if cat
        catname = cat['name']
        jiras << key if pid == catname.downcase
      end
    end
  end
  return jiras
end

def main()
  retirees = get_json(CTTEE_RETIRED)['retired']
  not_retired = ARGV - retirees.keys
  if not_retired.size > 0
    puts "The following projects are not recorded as retired: #{not_retired}"
  end

  #  TODO filter out done ones
  # process valid projects
  (ARGV - not_retired).each do |pid|
    puts "Processing #{pid}"
    meta = retirees[pid]
    bdates = get_board_date(meta['retired']).map{|d| Date.parse(d)}
    bdates = bdates.first if bdates.size == 1
    data = {
      retirement_date: bdates,
      attic_issue: 'ATTIC-nnn',
      attic_date: nil,
      attic_banner: true,
      # revived_date: nil,
      project_name: meta['display_name'],
      # project_longname: Where to find this?,
      project_description: meta['display_name'] + ' was a ' + meta['description'] + '.',
      board_resolution: true,
      board_reports: true,   
      downloads: true, # check if there are any?
    }
    data.delete(:project_name) if data[:project_name] == pid.capitalize # Not needed
    if has_svn pid
      data[:source_repositories] ||= []
      data[:source_repositories] << 
      {
        type: 'Subversion'
      }
    end

    has_git = get_json(GITREPOS)['projects'][pid]
    if has_git
      data[:source_repositories] ||= []
      data[:source_repositories] << 
      {
        type: 'Git'
      }
    end

    mlists = get_json(LISTSAO)['lists']["#{pid}.apache.org"]&.keys
    if mlists
      # ensure dev sorts first
      data[:mailing_lists] = mlists.sort_by {|l| l == 'dev' ? 'aaa' : l} if mlists.size > 0
    else
      $stderr.puts "No mailing lists found for #{pid}"
    end
    
    jiras = get_jiras pid
    if jiras.size > 0
      data[:issue_trackers] ||= []
      tracker =
      {
        type: 'JIRA'
      }
      tracker[:keys] = jiras.sort if jiras.size > 1 or jiras.first != pid.upcase
      data[:issue_trackers] << tracker
    end

    # TODO: Allow for Bugzilla and GitHub

    wikis = find_wikis pid
    if wikis.size > 0
      data[:wiki] = {
        type: 'CWIKI'
      }
      data[:wiki][:keys] = wikis if wikis.size > 1 or wikis.first != pid.upcase
    end

    dir = ENV['OUTPUT'] || '_data/projects' # Allow override for testing
    output = File.join(dir, "#{pid}.yaml")
    puts "Creating #{output}"
    content = YAML.safe_dump(data, permitted_classes: [Date], stringify_names: true, indentation: 4)
    # Massage the output to look more like existing files
    tmp = content.sub('project_description: ', "project_description: >-\n    ")
    File.write(output, tmp)
  end
end

if __FILE__ == $0
  JIRAS = get_json(JIRA)
  WIKIS = get_json(CWIKI_INFO, 'results')
  main
end
