#!/usr/bin/env python3

# Check UAS operator registration number

# Based on:
# Easy Access Rules for Unmanned Aircraft Systems
# Regulations (EU) 2019/947 and (EU) 2019/945
# AMC1 Article 14(6) Registration of UAS operators and 'certified' UAS
# https://www.easa.europa.eu/en/document-library/easy-access-rules/easy-access-rules-unmanned-aircraft-systems-regulations-eu
#
# https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm
# https://en.wikipedia.org/wiki/Luhn_algorithm

__author__ = "Gernot Walzl"
__date__ = "2026-01-03"

import argparse
import sys

chr_to_val = {
    '0': 0,
    '1': 1,
    '2': 2,
    '3': 3,
    '4': 4,
    '5': 5,
    '6': 6,
    '7': 7,
    '8': 8,
    '9': 9,
    'a': 10,
    'b': 11,
    'c': 12,
    'd': 13,
    'e': 14,
    'f': 15,
    'g': 16,
    'h': 17,
    'i': 18,
    'j': 19,
    'k': 20,
    'l': 21,
    'm': 22,
    'n': 23,
    'o': 24,
    'p': 25,
    'q': 26,
    'r': 27,
    's': 28,
    't': 29,
    'u': 30,
    'v': 31,
    'w': 32,
    'x': 33,
    'y': 34,
    'z': 35
}


def luhn_mod_n_checksum(alphanumerics, n=36):
    sum_digits = 0
    alphanums_reversed = alphanumerics[::-1]
    for idx, alphanum in enumerate(alphanums_reversed):
        code_points = chr_to_val[alphanum]
        if idx % 2 == 0:
            code_points *= 2
        if code_points >= n:
            code_points -= (n-1)
        sum_digits += code_points
    checksum = (n - (sum_digits % n)) % n
    return checksum


def main(uas_reg_num):
    # first three (3) alphanumerics (upper-case only) corresponding to
    # the ISO 3166 Alpha-3 code of the Member State of registration
    # country = uas_reg_num[0:3]

    # twelve (12) randomly generated characters that consist of alphanumerics
    # (lower-case only)
    alphanumerics = uas_reg_num[3:15]

    # one (1) character corresponding to the checksum
    checksum = uas_reg_num[15]

    # three (3) additional alphanumerics (lower-case only) called
    # 'secret digits'
    secret = uas_reg_num[17:20]

    # generate a checksum by applying the Luhn-mod-36 algorithm to the
    # fifteen (15) alphanumerics that result from the concatenation,
    # in the following order, of:
    # (1) the twelve (12) alphanumerics of the UAS operator registration number
    # (2) the three (3) randomly generated 'secret digits'
    checksum_expected = luhn_mod_n_checksum(alphanumerics + secret)

    result = 1
    if chr_to_val[checksum] == checksum_expected:
        result = 0
        print("OK")
    else:
        print("FAILED")
    return result


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'uas_reg_num', type=str,
        help="UAS operator registration number (example: FIN87astrdge12k8-xyz)")
    args = parser.parse_args()
    sys.exit(main(args.uas_reg_num))
