require 'gitlab'
require 'yaml'
require 'erb'
require 'date'
require_relative 'fiscal_date_helper'
require_relative 'milestone_helper'

dry_run = false
today = Date.today
project_id = ENV['CI_PROJECT_ID']
api_token = ENV['GITLAB_API_PRIVATE_TOKEN']

class IssueCreator
  def initialize(today)
    @today = today
  end

  def run(api_token, project_id)
    connect(api_token)
    puts 'Loading content from config/issues.yml'

    @issues = YAML.load(ERB.new(File.read('config/issues.yml')).result)

    puts 'Content loaded successfully.'
    puts 'Walking issues to create...'
    @issues['issues'].each do |issue|
      if issue['day_of_month']
        ## Using Day of Month Value
        today_date = @today.strftime('%-d')
        if today_date == issue['day_of_month'].to_s
          puts '* ' << issue['name'] << ' should be created on the ' << issue['day_of_month'].to_s << ' day of the month.'
          puts '** Today is the ' << today_date
          create(issue['name'], issue['template'], issue['scope'], "Monthly", project_id)
        end
      end
      if issue['day_of_week']
        ## Using Day of week value
        today_day = @today.strftime('%a')
        if today_day == issue['day_of_week'].to_s
          puts '* ' << issue['name'] << ' should be created every ' << issue['day_of_week'].to_s << '.'
          puts '** Today is ' << today_day
          create(issue['name'], issue['template'], issue['scope'], 'Weekly', project_id)
        end
      end
      if issue['quarterly']
        ## Using Quarterly
        fiscal_quarter_start = %w[02 05 08 11]
        fiscal_quarter_end = %w[04 07 10 01]
        month = @today.strftime('%m')
        today_date = @today.strftime('%d')

        # First Day of Quarter
        if issue['quarterly'] == 'first_day_of_quarter' && today_date == '01' && (fiscal_quarter_start.include? month)
          create(issue['name'], issue['template'], issue['scope'], 'Quarterly', project_id)
        end

        # Last Day of Quarter
        if issue['quarterly'] == 'last_day_of_quarter' && today_date == '28' && (fiscal_quarter_end.include? month)
          create(issue['name'], issue['template'], issue['scope'], 'Quarterly', project_id)
        end

        # First Day of Last Month of Quarter
        if issue['quarterly'] == 'first_day_of_last_month_of_quarter' && today_date == '01' && (fiscal_quarter_end.include? month)
          create(issue['name'], issue['template'], issue['scope'], 'Quarterly', project_id)
        end
      end
      if issue['day_of_year']
        ## Using Yearly
        days = Array(issue['day_of_year'])
        if days.include? @today.yday
          create(issue['name'], issue['template'], issue['scope'], issue['frequency'] || 'Yearly', project_id)
        end
      end
    end
    puts 'Run Complete.'
  end

  def connect(api_token)
    puts 'Connecting to GitLab...'
    @gitlab = Gitlab.client(
      endpoint: 'https://gitlab.com/api/v4',
      private_token: api_token
    )
    @user = @gitlab.user
    puts 'Connection successful. Connected user email: ' << @user.email
  end

  def upcoming_milestone
    @upcoming_milestone ||= MilestoneHelper.upcoming_milestone
    @upcoming_milestone
  end

  def previous_milestone
    @previous_milestone ||= MilestoneHelper.previous_milestone
    @previous_milestone
  end


  # replace keywords MILESTONE and PREVIOUS_MILESTONE in a string for a numeric value
  def replace_milestone(text = "")
    text = text.gsub('<MILESTONE>', upcoming_milestone)
    text = text.gsub('<PREVIOUS_MILESTONE>', previous_milestone)
    text
  end

  def create(name, template_name, scope, frequency, project_id)
    frequency_text = ''
    case frequency
    when 'Monthly'
      frequency_text = Date::MONTHNAMES[@today.month]
    when 'Weekly'
      frequency_text = 'Week ' + @today.cweek.to_s
    when 'Quarterly'
      frequency_text = 'Quarterly'
    when 'Yearly'
      frequency_text = 'Yearly'
    when 'Biannually'
      frequency_text = 'Biannually'
    end
    if scope == 'all'
      ## implies we don't need to use an ERB template just regular issue templates
      template = File.open('.gitlab/issue_templates/' << template_name).read
      puts '** Template loaded...'
      description = ERB.new(template, 0, '>').result(binding)
      puts '** Description generated...'

      description = replace_milestone(description)
      issue_title = replace_milestone(name)
      puts '** Milestone keywords replaced...'

      @gitlab.create_issue(project_id, issue_title + ' : ' + frequency_text, { description: description, assignee_id: @user.id })
      puts '** ' << issue_title << ' issue created.'
    end
  end
end

# Mock GitLab user and service
class UserMock
  def initialize
    @email = 'mockuser@gitlab.com'
    @id = 1234
  end
  attr_accessor :email, :id
end
class GitLabMock
  def initialize
    @user = UserMock.new()
  end

  def create_issue(project, title, options)
    puts 'Would have created issue:'
    puts '  Project: ' + project
    puts '  Title:   ' + title
    puts '  Content: \n' + options[:description] + '\n\n'
  end
  attr_accessor :user
end
# Override issue creator to use GitLab mock
class IssueCreatorTest < IssueCreator
  def connect(api_token)
    puts 'Connecting to GitLab...'
    @gitlab = GitLabMock.new()
    @user = @gitlab.user
    puts 'Connection successful. Connected user email: ' << @user.email
  end
end

if $PROGRAM_NAME == __FILE__
  # Override with mock if we are doing a dry run
  ARGV.each do |arg|
    if arg == '--dry-run'
      dry_run = true
      api_token = 'mocktoken'
      project_id = 'mockproject'
      (1..12).each do |m|
        # Simulate every month of the year
        (1..28).each do |d|
          # Simulate every day of the month
          # No day_of_month in issues.yml are after the 28th which makes it simple
          # to not trigger an invalid date here in this dry-run test.
          today = Date::strptime(d.to_s + '-' + m.to_s + '-2020', '%d-%m-%Y')
          if today
            issue_creator = IssueCreatorTest.new(today)
            issue_creator.run(api_token, project_id)
          end
        end
      end
    end
  end
  unless dry_run
    issue_creator = IssueCreator.new(today)
    issue_creator.run(api_token, project_id)
  end
end
