#!/usr/bin/python3
"""
Creates Github Releases Notes with content hashes
"""

import argparse
import logging
import os
import hashlib
import glob

from github import Github, GithubException, UnknownObjectException

FORMAT = "%(levelname)s - %(asctime)s: %(message)s"
logging.basicConfig(format=FORMAT)

CLOUDFLARED_REPO = os.environ.get("GITHUB_REPO", "cloudflare/cloudflared")
GITHUB_CONFLICT_CODE = "already_exists"

def get_sha256(filename):
    """ get the sha256 of a file """
    sha256_hash = hashlib.sha256()
    with open(filename,"rb") as f:
        for byte_block in iter(lambda: f.read(4096),b""):
            sha256_hash.update(byte_block)
        return sha256_hash.hexdigest()


def update_or_add_message(msg, name, sha):
    """ 
    updates or builds the github version message for each new asset's sha256. 
    Searches the existing message string to update or create. 
    """
    new_text = '{0}: {1}\n'.format(name, sha)
    start = msg.find(name)
    if (start != -1):
        end = msg.find("\n", start)
        if (end != -1):
            return msg.replace(msg[start:end+1], new_text)
    back = msg.rfind("```")
    if (back != -1):
        return '{0}{1}```'.format(msg[:back], new_text)
    return '{0} \n### SHA256 Checksums:\n```\n{1}```'.format(msg, new_text)

def get_release(repo, version):
    """ Get a Github Release matching the version tag. """
    try:
        release = repo.get_release(version)
        logging.info("Release %s found", version)
        return release
    except UnknownObjectException:
        logging.info("Release %s not found", version)


def parse_args():
    """ Parse and validate args """
    parser = argparse.ArgumentParser(
        description="Creates Github Releases and uploads assets."
    )
    parser.add_argument(
        "--api-key", default=os.environ.get("API_KEY"), help="Github API key"
    )
    parser.add_argument(
        "--release-version",
        metavar="version",
        default=os.environ.get("VERSION"),
        help="Release version",
    )
    parser.add_argument(
        "--dry-run", action="store_true", help="Do not modify the release message"
    )

    args = parser.parse_args()
    is_valid = True
    if not args.release_version:
        logging.error("Missing release version")
        is_valid = False

    if not args.api_key:
        logging.error("Missing API key")
        is_valid = False

    if is_valid:
        return args

    parser.print_usage()
    exit(1)


def main():
    """ Attempts to update the Github Release message with the github asset's checksums """
    try:
        args = parse_args()
        client = Github(args.api_key)
        repo = client.get_repo(CLOUDFLARED_REPO)
        release = get_release(repo, args.release_version)

        msg = release.body

        for filepath in glob.glob("artifacts/*"):
            pkg_hash = get_sha256(filepath)
            # add the sha256 of the new artifact to the release message body
            name = os.path.basename(filepath)
            msg = update_or_add_message(msg, name, pkg_hash)

        if args.dry_run:
            logging.info("Skipping asset upload because of dry-run")
            return

        # update the release body text
        release.update_release(args.release_version, msg)

    except Exception as e:
        logging.exception(e)
        exit(1)


main()