#!/usr/bin/env python3

"""Go over all open stabilization or keywording bugs, and check for done bugs."""

import json
import sys
import urllib.request as urllib
from typing import TypedDict
from urllib.parse import urlencode

from pkgcore.ebuild.atom import atom
from pkgcore.ebuild.errors import MalformedAtom
from pkgcore.util import commandline

argparser = commandline.ArgumentParser(version=False, description=__doc__)
argparser.add_argument(
    "--api-key",
    metavar="KEY",
    required=True,
    help="Bugzilla API key",
    docs="""
        The Bugzilla API key to use for authentication. Used mainly to overcome
        rate limiting done by bugzilla server. This tool doesn't perform any
        bug editing, just fetching info for the bug.
    """,
)


class BugInfo(TypedDict):
    id: int
    cf_stabilisation_atoms: str
    component: str
    cc: list[str]


@argparser.bind_final_check
def check_args(parser, namespace):
    namespace.repo = namespace.domain.ebuild_repos


def fetch_bugs(api_key: str) -> tuple[BugInfo, ...]:
    params = urlencode(
        (
            ("Bugzilla_api_key", api_key),
            ("component", "Stabilization"),
            ("component", "Keywording"),
            ("include_fields", ",".join(BugInfo.__annotations__)),
            ("bug_status", "UNCONFIRMED"),
            ("bug_status", "CONFIRMED"),
            ("bug_status", "IN_PROGRESS"),
            ("f1", "flagtypes.name"),
            ("o1", "anywords"),
            ("v1", "sanity-check+"),
        )
    )
    with urllib.urlopen(
        "https://bugs.gentoo.org/rest/bug?" + params, timeout=30
    ) as response:
        return tuple(json.loads(response.read().decode("utf-8")).get("bugs", []))


def parse_atom(pkg: str):
    try:
        return atom(pkg)
    except MalformedAtom as exc:
        try:
            return atom(f"={pkg}")
        except MalformedAtom:
            raise exc


def collect_packages(repo, bug: BugInfo):
    return tuple(
        pkg
        for a in bug["cf_stabilisation_atoms"].splitlines()
        if (b := " ".join(a.split()))
        for pkg in repo.itermatch(parse_atom(b.split(" ", 1)[0]))
    )


@argparser.bind_main_func
def main(options, out, err):
    for bug in fetch_bugs(options.api_key):
        try:
            pkgs = collect_packages(options.repo, bug)
            if not pkgs:
                continue
            for cc in bug["cc"]:
                cc = cc.removesuffix("@gentoo.org")
                if bug["component"] == "Keywording":
                    continue  # skip keywording for now, the heuristic is wrong
                if all(cc in pkg.keywords for pkg in pkgs):
                    out.write(
                        out.fg("yellow"),
                        f"https://bugs.gentoo.org/{bug['id']}, cc: {cc}, all packages are done",
                        out.reset,
                        " -> ",
                        f"nattka resolve -a {cc} {bug['id']}",
                    )
                if bug["component"] == "Keywording" and all(
                    f"~{cc}" in pkg.keywords for pkg in pkgs
                ):
                    out.write(
                        out.fg("yellow"),
                        f"https://bugs.gentoo.org/{bug['id']}, cc: ~{cc}, all packages are done",
                        out.reset,
                        " -> ",
                        f"nattka resolve -a {cc} {bug['id']}",
                    )
        except MalformedAtom as exc:
            err.write(
                err.fg("red"),
                f">>> Malformed bug {bug['id']} with atoms: {', '.join(bug['cf_stabilisation_atoms'].splitlines())}",
                err.reset,
                str(exc),
            )


if __name__ == "__main__":
    tool = commandline.Tool(argparser)
    sys.exit(tool())
