require 'date'
require 'erb'
require './lib/gitlab_api'

class DescriptionTemplate
  def initialize(team, release, api_client:)
    @team = team
    @release = release
    @api_client = api_client
  end

  def issue_query_prefix
    # https://docs.gitlab.com/ee/api/issues.html
    if team.query_all_groups?
      'issues?scope=all&'
    else
      'groups/gitlab-org/issues?' # The default queries gitlab-org only
    end
  end

  def merge_request_query_prefix
    # https://docs.gitlab.com/ee/api/merge_requests.html
    if team.query_all_groups?
      'merge_requests?scope=all&'
    else
      'groups/gitlab-org/merge_requests?'  # The default queries gitlab-org only
    end
  end

  def template_issue_url_prefix
    if team.query_all_groups?
      'dashboard/issues?scope=all&' # Accounts for other projects (e.g. gitlab-services), scope=all ensures issues created by others are included
    else
      'groups/gitlab-org/-/issues?' # The default queries gitlab-org only
    end
  end

  def result_with_hash(hash)
    binding_hash = {
      team: team,
      release: release['title'],
      due_date: Date.today.next_month.strftime('%Y-%m-26')
    }

    hash[:mention_owners] = self.mention_team_owners

    if hash[:updating_description]
      binding_hash.merge!(
        due_date: Date.today.strftime('%Y-%m-26'),
        deliverables: deliverables,
        features: features,
        bugs: bugs,
        issues: issues,
        issue_count: issue_count,
        total_weight: total_weight,
        merge_request_count: merge_request_count,
        slipped: slipped,
        current_retrospective: current_retrospective,
        issue_url_prefix: hash[:query_all_groups] === true ? 'dashboard/issues?scope=all&' : 'groups/gitlab-org/-/issues?',
        vsa_url_prefix: 'groups/gitlab-org/-/analytics/value_stream_analytics?',
        release_start_date: release.fetch('start_date', nil),
        release_due_date: release.fetch('due_date', nil),
      )
      if team.additional_label
        hash[:additional_label] = team.additional_label
        hash[:issues_with_additional_label] = issues_with_additional_label
      end
    end

    binding_hash.merge!(hash)

    include_template = lambda do |filename|
      load_template(filename).result_with_hash(binding_hash)
    end

    binding_hash[:include_template] = include_template

    template.result_with_hash(binding_hash)
  end

  def current_issue_url
    current_retrospective&.fetch('web_url') || 'http://does.not/exist'
  end

  def current_api_path
    "#{project_issues_path}/#{current_retrospective&.fetch('iid') || -1}"
  end

  def current_retrospectives_api_path(extra_labels = [])
    labels = ['retrospective'].concat(extra_labels)
    "#{project_issues_path}?labels=#{labels.join(',')}&state=opened&search=#{release['title']}"
  end

  def deliverables
    @deliverables ||=
      api_client.get("#{issue_query_prefix}labels=#{team.label},Deliverable&state=closed&milestone=#{release['title']}")
  end

  def features
    @features ||=
      api_client.get("#{issue_query_prefix}labels=#{team.label},type::feature&state=closed&milestone=#{release['title']}")
  end

  def bugs
    @bugs ||=
      api_client.get("#{issue_query_prefix}labels=#{team.label},type::bug&state=closed&milestone=#{release['title']}")
  end

  def slipped
    @slipped ||=
      api_client.get("#{issue_query_prefix}labels=#{team.label},missed%3A#{release['title']}")
  end

  def issues_with_additional_label
    @issues_with_additional_label ||=
      api_client.get("#{issue_query_prefix}labels=#{team.label},#{team.additional_label}&state=closed&milestone=#{release['title']}")
  end

  def current_retrospective
    @current_retrospective ||= current_retrospectives.first
  end

  def current_retrospectives
    if current_retrospectives_with_team_label.size > 0
      current_retrospectives_with_team_label
    else
      current_retrospectives_without_team_label
    end
  end

  def current_retrospectives_with_team_label
    @current_retrospectives_with_team_label ||= api_client.get(current_retrospectives_api_path([team.label]))
  end

  def current_retrospectives_without_team_label
    @current_retrospectives_without_team_label ||= api_client.get(current_retrospectives_api_path)
  end

  def issues
    @issues ||= api_client.get("#{issue_query_prefix}labels=#{team.label}&state=closed&milestone=#{release['title']}")
  end

  def issue_count
    @issue_count ||= issues.headers['X-Total'].to_i
  end

  def total_weight
    @total_weight ||= begin
      sum = issues.sum { |i| i['weight'] || 0 }

      return sum if issues.count == issues.headers['X-Total'].to_i

      "#{sum}+"
    end
  end

  def merge_request_count
    @merge_request_count ||=
      api_client.count("#{merge_request_query_prefix}labels=#{team.label}&state=merged&milestone=#{release['title']}")
  end

  def mention_team_owners
    owners = team.owner
    owners = [owners] unless owners.is_a?(Array)
    "@" + owners.join(' @')
  end

  def project_issues_path
    "projects/gl-retrospectives%2F#{team.project}/issues"
  end

  private

  attr_reader :team, :release, :api_client

  def template
    @template ||= load_template(team.template)
  end

  def load_template(filename)
    ERB.new(File.read("templates/#{filename}.erb"), trim_mode: '<>')
  end
end
