# pylint: disable=invalid-name
'''
List GitHub Actions versions used and latest versions
'''
import json
import os
import ssl
import urllib.request
from json.decoder import JSONDecodeError

import yaml

allACTIONS = {}
listACTIONS = []

VER_WIDTH = 10
NAME_WIDTH = 40
LINE_WIDTH = 1 + NAME_WIDTH + 5 + VER_WIDTH + 5 + VER_WIDTH + 1

def process_walk(key, node):
    '''
    Process walking through the array
    '''
    global allACTIONS
    global listACTIONS
    if key == "uses":
        action = node.split('@')
        version = ""
        if '@' in node:
            version = action[1]
        action = action[0]
        if action not in allACTIONS:
            allACTIONS[action] = {
                "versions": [],
                "latest": ""
            }
        allACTIONS[action]["versions"].append(version)
        allACTIONS[action]["versions"] = list(
            set(
                allACTIONS[action]["versions"]
            )
        )
        listACTIONS.append(node)


def walk(key, node):
    '''
    How to walk through the array
    '''
    if isinstance(node, dict):
        return {k: walk(k, v) for k, v in node.items()}
    elif isinstance(node, list):
        return [walk(key, x) for x in node]
    else:
        return process_walk(key, node)


for r, d, f in os.walk(os.path.join(".", ".github")):
    if "actions" in r or "workflows" in r:
        for filename in f:
            # if it's not a YAML or it's turned off, skip it
            if (".yml" not in filename and ".yaml" not in filename) or (".off" in filename):
                continue
            listACTIONS = []
            # print filename
            filename_line = "-" * (len(os.path.join(r, filename)) + 2)
            print(
                " " +
                filename_line +
                " "
            )
            print("| " + os.path.join(r, filename) + " |")
            # read the file
            with(open(os.path.join(r, filename), "r", encoding="utf-8")) as yamlFile:
                print(
                    "|" +
                    filename_line +
                    "-" +
                    ("-" * (LINE_WIDTH - len(filename_line) + 1)) +
                    " "
                )
                yml = yaml.safe_load(yamlFile)
                walk("uses", yml)
                dictACTIONS = {}
                for k in sorted(list(set(listACTIONS))):
                    action = k.split('@')[0]
                    version = k.split('@')[1] if '@' in k else ""
                    latest = ""
                    # if it's not a location action, get the latest version number
                    if "./." not in action:
                        apiURL = f"https://api.github.com/repos/{action}/releases/latest"
                        if True:
                            apiReq = None
                            try:
                                apiReq = urllib.request.urlopen(
                                    apiURL,
                                    context=ssl._create_unverified_context()
                                )
                            except urllib.error.HTTPError as e:
                                if e.code != 403:
                                    print(e.code, apiURL)
                            if apiReq:
                                apiRes = {}
                                try:
                                    apiRes = json.loads(
                                        apiReq.read().decode("utf-8"))
                                except JSONDecodeError as e:
                                    raise ValueError("API Request failed: " + apiURL)
                                if apiRes:
                                    latest = apiRes["tag_name"] if "tag_name" in apiRes else ""
                                    if latest != "":
                                        allACTIONS[action]["latest"] = latest
                    dictACTIONS[action] = version
                # print action name and version info
                for action, version in dictACTIONS.items():
                    print(
                        "| " + \
                        f"{action.ljust(NAME_WIDTH)}" + \
                        "\t" + \
                        f"{(version or 'N/A').ljust(VER_WIDTH)}" + \
                        "\t" + \
                        f"{(allACTIONS[action]['latest'] or 'N/A').ljust(VER_WIDTH)}" + \
                        " |"
                    )
                print(
                    " " +
                    ("-" * (LINE_WIDTH + 2)) +
                    " "
                )
            print("")

# print outdated versions summary
first = True
outdated = False
for action, actionData in allACTIONS.items():
    if len(actionData["versions"]) > 0:
        if actionData["latest"] != "" and actionData["versions"][0] != actionData["latest"]:
            outdated = True
            if first:
                first = False
                filename_line = "-" * (len("| Outdated |"))
                print(
                    " " +
                    filename_line +
                    " "
                )
                print("| Outdated |")
                print(
                    "|" +
                    filename_line +
                    "-" +
                    ("-" * (LINE_WIDTH - len(filename_line) + 1)) +
                    " "
                )
            print(
                "| " + \
                f"{action.ljust(40)}" + \
                "\t" + \
                f"{(','.join(actionData['versions']) or 'N/A').ljust(10)}" + \
                "\t" + \
                f"{actionData['latest'].ljust(10)}" + \
                " |"
            )
if outdated:
    print(
        " " +
        ("-" * (LINE_WIDTH + 2)) +
        " "
    )
