#!/usr/bin/env python

"""
Update a pinned github repository.

Pass this path to a JSON file and it will update it to the latest
version of the branch it specifies. You can also pass a different
branch or repository owner, which will update the file to point at
the new branch/repository, and update to the latest version.
"""

import argparse
import json
from pathlib import Path

import httpx
from ps_tools import get_url_hash

HASH_TYPE = "sha512"

ARCHIVE_TEMPLATE = "https://api.github.com/repos/{owner}/{repo}/tarball/{rev}"
BRANCH_TEMPLATE = (
    "https://api.github.com/repos/{owner}/{repo}/commits/{branch}"
)


def get_github_commit(config):
    response = httpx.get(BRANCH_TEMPLATE.format(**config))
    response.raise_for_status()
    return response.json()["sha"]


def get_github_archive_url(config):
    return ARCHIVE_TEMPLATE.format(**config)


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "repo_file",
        metavar="repo-file",
        type=Path,
        help="JSON file with pinned configuration.",
    )
    parser.add_argument(
        "--branch",
        type=str,
        help="Branch to update to.",
    )
    parser.add_argument(
        "--owner",
        type=str,
        help="Repository owner to update to.",
    )
    parser.add_argument(
        "--rev",
        type=str,
        help="Revision to pin.",
    )
    parser.add_argument(
        "--dry-run",
        action="store_true",
    )
    args = parser.parse_args()

    repo_file = args.repo_file
    config = json.loads(repo_file.read_text())

    for key in ["owner", "branch"]:
        if getattr(args, key) is not None:
            config[key] = getattr(args, key)

    if args.rev is not None:
        config["rev"] = args.rev
    else:
        config["rev"] = get_github_commit(config)

    archive_url = get_github_archive_url(config)
    config.update(get_url_hash(HASH_TYPE, "source", archive_url))

    output = json.dumps(config, indent=2)
    if args.dry_run:
        print(output)
    else:
        repo_file.write_text(output)


if __name__ == "__main__":
    main()