#!/usr/bin/python3
# Find the next thing to work on for proposed-migration
# Copyright (C) 2023 Canonical Ltd.
# Author: Steve Langasek <steve.langasek@ubuntu.com>

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License, version 3.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import lzma
import sys
import webbrowser
from argparse import ArgumentParser

import yaml
from launchpadlib.launchpad import Launchpad

from ubuntutools.utils import get_url

# proposed-migration is only concerned with the devel series; unlike other
# tools, don't make this configurable
excuses_url = "https://ubuntu-archive-team.ubuntu.com/proposed-migration/update_excuses.yaml.xz"


def get_proposed_version(excuses, package):
    for k in excuses["sources"]:
        if k["source"] == package:
            return k.get("new-version")
    return None


def claim_excuses_bug(launchpad, bug, package):
    print("LP: #%d: %s" % (bug.id, bug.title))
    ubuntu = launchpad.distributions["ubuntu"]
    series = ubuntu.current_series.fullseriesname

    for task in bug.bug_tasks:
        # targeting to a series doesn't make the default task disappear,
        # it just makes it useless
        if task.bug_target_name == "%s (%s)" % (package, series):
            our_task = task
            break
        elif task.bug_target_name == "%s (Ubuntu)" % package:
            our_task = task

    if our_task.assignee == launchpad.me:
        print("Bug already assigned to you.")
        return True
    elif our_task.assignee:
        print("Currently assigned to %s" % our_task.assignee.name)

    print("""Do you want to claim this bug? [yN] """, end="")
    sys.stdout.flush()
    response = sys.stdin.readline()
    if response.strip().lower().startswith("y"):
        our_task.assignee = launchpad.me
        our_task.lp_save()
        return True

    return False


def create_excuses_bug(launchpad, package, version):
    print("Will open a new bug")
    bug = launchpad.bugs.createBug(
        title="proposed-migration for %s %s" % (package, version),
        tags=("update-excuse"),
        target="https://api.launchpad.net/devel/ubuntu/+source/%s" % package,
        description="%s %s is stuck in -proposed." % (package, version),
    )

    task = bug.bug_tasks[0]
    task.assignee = launchpad.me
    task.lp_save()

    print("Opening %s in browser" % bug.web_link)
    webbrowser.open(bug.web_link)
    return bug


def has_excuses_bugs(launchpad, package):
    ubuntu = launchpad.distributions["ubuntu"]
    pkg = ubuntu.getSourcePackage(name=package)
    if not pkg:
        raise ValueError(f"No such source package: {package}")

    tasks = pkg.searchTasks(tags=["update-excuse"], order_by=["id"])

    bugs = [task.bug for task in tasks]
    if not bugs:
        return False

    if len(bugs) == 1:
        print("There is 1 open update-excuse bug against %s" % package)
    else:
        print("There are %d open update-excuse bugs against %s" % (len(bugs), package))

    for bug in bugs:
        if claim_excuses_bug(launchpad, bug, package):
            return True

    return True


def main():
    parser = ArgumentParser()
    parser.add_argument("-l", "--launchpad", dest="launchpad_instance", default="production")
    parser.add_argument(
        "-v", "--verbose", default=False, action="store_true", help="be more verbose"
    )
    parser.add_argument("package", nargs="?", help="act on this package only")
    args = parser.parse_args()

    args.launchpad = Launchpad.login_with("pm-helper", args.launchpad_instance, version="devel")

    f = get_url(excuses_url, False)
    with lzma.open(f) as lzma_f:
        excuses = yaml.load(lzma_f, Loader=yaml.CSafeLoader)

    if args.package:
        try:
            if not has_excuses_bugs(args.launchpad, args.package):
                proposed_version = get_proposed_version(excuses, args.package)
                if not proposed_version:
                    print("Package %s not found in -proposed." % args.package)
                    sys.exit(1)
                create_excuses_bug(args.launchpad, args.package, proposed_version)
        except ValueError as e:
            sys.stderr.write(f"{e}\n")
    else:
        pass  # for now


if __name__ == "__main__":
    sys.exit(main())