#!/usr/bin/env python3

# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. 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.

import os
import sys

import github3

ORG = "elastic"
REPO = "rally"


def find_milestone(repo, title):
    for m in repo.milestones(state="open", sort="due_date"):
        if m.title == title:
            return m
    return None


def print_category(heading, issue_list):
    if issue_list:
        print("#### %s\n" % heading)
        for issue in issue_list:
            print_issue(issue)
        print("")


def print_issue(issue):
    breaking_hint = " (Breaking)" if labelled(issue, label_name="breaking") else ""
    print("* [#%s](%s)%s: %s" % (str(issue.number), issue.html_url, breaking_hint, issue.title))


def labelled(issue, label_name):
    for label in issue.labels():
        if label.name == label_name:
            return True
    return False


def is_pr(issue):
    """

    :param issue: an issue. May also be a PR.
    :return: True iff the issue is actually a PR.
    """
    return issue.html_url and "pull" in issue.html_url and issue.pull_request().merged


def pr_list(i):
    return [item for item in i if is_pr(item)]


def list_subtract(a, b):
    return [item for item in a if item not in b]


def prs(gh, milestone, with_labels, without_labels=None):
    prs_labelled = pr_list(gh.issues_on(ORG, REPO, milestone=milestone.number, state="closed", labels=with_labels))
    filtered_prs = prs_labelled
    if without_labels:
        for label in without_labels:
            prs_not_labelled = pr_list(gh.issues_on(ORG, REPO, milestone=milestone.number, state="closed", labels=label))
            filtered_prs = list_subtract(filtered_prs, prs_not_labelled)
    return filtered_prs


def main():
    if len(sys.argv) != 2:
        print("usage: %s milestone" % sys.argv[0], file=sys.stderr)
        exit(1)

    milestone_name = sys.argv[1]

    # requires a personal Github access token with permission `public_repo` (see https://github.com/settings/tokens)
    gh = github3.login(token=open("%s/.github/rally_release_changelog.token" % os.getenv("HOME")).readline().strip())

    rally_repo = gh.repository(ORG, REPO)

    milestone = find_milestone(rally_repo, title=milestone_name)
    if not milestone:
        print("No open milestone named [%s] found." % milestone_name, file=sys.stderr)
        exit(2)
    if milestone.open_issues > 0:
        print("There are [%d] open issues on milestone [%s]. Aborting..." % (milestone.open_issues, milestone_name), file=sys.stderr)
        exit(2)

    print("### %s\n" % milestone_name)

    print_category("Highlights", prs(gh, milestone, with_labels="highlight"))
    print_category(
        "Enhancements", prs(gh, milestone, with_labels="enhancement", without_labels=[":Docs", "highlight", ":internal", ":misc"])
    )
    print_category("Bug Fixes", prs(gh, milestone, with_labels="bug", without_labels=[":Docs", "highlight", ":internal", ":misc"]))
    print_category("Doc Changes", prs(gh, milestone, with_labels=":Docs", without_labels=["highlight", ":misc"]))
    print_category("Miscellaneous Changes", prs(gh, milestone, with_labels=":misc", without_labels=[":internal"]))


if __name__ == "__main__":
    main()
