#!/usr/bin/env python3

from __future__ import annotations

from typing import List
from typing import Tuple

import subprocess
import sys

ALLOWED_TAGS = [
    'ci',
    'cfix',
    'new',
    'cq',
    'feat',
    'fix',
    'perf',
    'refactor',
    'chore',
    'change',
    'release',
    'other',
    'imprv',
]


def parse_args() -> Tuple[str, str, str]:
    ref_name = sys.argv[1]
    old_ref = sys.argv[2]
    new_ref = sys.argv[3]
    return ref_name, old_ref, new_ref


def get_commit_subject(sha: str) -> str:
    data = subprocess.check_output(
        ['git', 'log', '-1', '--pretty=format:%s', sha])
    return data.decode()


def get_commit_shas(start_ref: str, end_ref: str) -> List[str]:
    arg = f'{start_ref}..{end_ref}'
    data = subprocess.check_output(['git', 'rev-list', arg])
    text = data.decode()
    text = text.strip()
    return text.split('\n')


def enforce_message_rules(subject: str) -> None:
    try:
        tag, subject = subject.split(': ', maxsplit=1)
    except ValueError:
        print('Unknown commit message tag:', subject)
        sys.exit(1)

    if tag not in ALLOWED_TAGS:
        print('Unknown commit message tag:', tag)
        sys.exit(1)

    if tag == 'release':
        if not subject[0].isdigit():
            print('Release commits should be of the form "release: X.X.X"')
            sys.exit(1)
        return

    if not subject[0].isupper():
        print('First letter after tag must be uppercase')
        sys.exit(1)


def main(args: Tuple[str, str, str]) -> None:
    ref_name, old_ref, new_ref = args
    print('UPDATE', ref_name, old_ref, new_ref)

    if ref_name != 'refs/heads/master':
        # We enforce only for master branch
        return

    shas = get_commit_shas(old_ref, new_ref)
    for sha in shas:
        subject = get_commit_subject(sha)
        enforce_message_rules(subject)


if __name__ == "__main__":
    args = parse_args()
    main(args)
