#!/usr/bin/env python3
"""
CLI tool for building Pakks from folders.
"""

import hashlib
from argparse import ArgumentParser
import pakk as pakker

if __name__ == "__main__":

    CLI = ArgumentParser()
    SUB_PARSERS = CLI.add_subparsers(dest="subcommand")

    def subcommand(args=[], parent=SUB_PARSERS):
        def decorator(func):
            parser = parent.add_parser(func.__name__, description=func.__doc__)
            for arg in args:
                parser.add_argument(*arg[0], **arg[1])
            parser.set_defaults(func=func)
        return decorator

    def argument(*name_or_flags, **kwargs):
        return ([*name_or_flags], kwargs)

    @subcommand(args=[
        argument("-o", "--output", dest="output", help="output path of the pakk file."),
        argument("-p", "--password", dest="password", help="password used to encrypt the contents of the pakk. Defaults to 'IsPakked'. It is HIGHLY recommended that you supply your own secure password with high entropy for each pakk.", default="IsPakked", type=str),
        argument("-c", "--chunksize", dest="chunksize", help="maximum amount of bytes to encrypt at once when pakking files in the folder. Must be an integer multiple of 1024. Defaults to 64*1024", default=64*1024, type=int),
        argument("input", help="input folder to encrypt and pakk."),
    ])
    def pakk(args):
        """
        Encrypts the contents of a specified folder and packs the encrypted content into a single pakk.
        """
        if args.chunksize % 1024 != 0:
            CLI.error("--chunksize must be a multiple of 1024")
        key = hashlib.sha256(args.password.encode("utf-8")).digest()
        pakker.pakk_folder(key=key, folder=args.input, outfile=args.output, chunksize=args.chunksize)

    @subcommand(args=[
        argument("-o", "--output", dest="output", help="path of the folder to output the pakk contents to."),
        argument("-p", "--password", dest="password", help="password used to decrypt the contents of the pakk. Must be the same password used when the pakk was created, otherwise decryption will fail. Defaults to 'IsPakked'. It is HIGHLY recommended that you supply your own secure password with high entropy for each pakk.", default="IsPakked", type=str),
        argument("-c", "--chunksize", dest="chunksize", help="maximum amount of bytes to decrypt at once when unpakking files in the folder. Must be an integer multiple of 1024. Defaults to 24*1024", default=24*1024, type=int),
        argument("input", help="input pakk file to decrypt and unpakk."),
    ])
    def unpakk(args):
        """
        Decrypts the contents of a specified pakk and unpacks it into an identical folder structure as was originally packed.
        """
        if args.chunksize % 1024 != 0:
            CLI.error("--chunksize must be a multiple of 1024")
        key = hashlib.sha256(args.password.encode("utf-8")).digest()
        pakker.unpakk_folder(key=key, pakk_file=args.input, outfolder=args.output, chunksize=args.chunksize)

    def main():
        args = CLI.parse_args()
        if not args.subcommand:
            CLI.print_help()
        else:
            args.func(args)

    main()
