#!python
import os
import sys
import shutil
import argparse
from glob import glob
from tqdm import tqdm

from abraia import config
from abraia import Abraia
from abraia import APIError

abraia = Abraia(folder='batch/')


def process_info():
    print('Abraia CLI v0.6.1')
    try:
        user = abraia.user()
        print('Name:', user.get('name'))
        print('Email:', user.get('email'))
        print('Credits:', user.get('credits'))
    except APIError as error:
        print('Error', error.code, error.message)


def process_configure():
    api_key, api_secret = config.load_auth()
    abraia_key = config.base64encode(
        '{}:{}'.format(api_key, api_secret)) if api_key and api_secret else ''
    key = input('Abraia Key [{}]: '.format(abraia_key))
    abraia_key = abraia_key if key == '' else key
    api_key, api_secret = config.base64decode(abraia_key).split(':')
    config.save_auth(api_key, api_secret)


def input_files(path):
    path = os.path.join(path, '**/*') if os.path.isdir(path) else path
    return glob(path, recursive=True)


def process_optimize(args):
    path = args['path']
    dest = args.get('dest')
    format = args.get('format')
    filenames = input_files(path)
    dirname = path.rstrip('/').rstrip('\\') if os.path.isdir(path) else None
    if len(filenames):
        for filename in tqdm(filenames, unit='file'):
            # TODO: Add parse_output function
            path, name = os.path.split(filename)
            nam, ext = os.path.splitext(name)
            oext = format if format is not None else ext
            fileout = os.path.join(path, nam+'_o'+oext)
            if dirname:
                relpath = os.path.relpath(path, dirname)
                if not os.path.exists(os.path.join(dirname+'_o', relpath)):
                    os.makedirs(os.path.join(dirname+'_o', relpath))
                fileout = os.path.join(dirname+'_o', relpath, nam+oext)
            if dest is not None:
                fileout = dest
                root, oext = os.path.splitext(fileout)
            if ext.lower() in config.IMAGE_EXTS and oext.lower() in config.IMAGE_EXTS:
                process_file(filename, fileout, args)
                if ext == oext and os.path.getsize(fileout) > os.path.getsize(filename):
                    shutil.copy2(filename, fileout)
                sizein = os.path.getsize(filename) / 1024
                sizeout = os.path.getsize(fileout) / 1024
                tqdm.write('[{3:04.1f}%] {1:6.1f}KB -> {2:6.1f}KB ({0})'.format(
                    os.path.split(fileout)[1], sizein, sizeout, 100 * (1 - sizeout / sizein)))
            else:
                shutil.copy2(filename, fileout)
    else:
        fileout = os.path.split(path) if dest is None else dest
        process_url(path, fileout, args)


def process_file(path, fileout, args):
    try:
        abraia.from_file(path).process(args).to_file(fileout)
    except APIError as error:
        print('Error', error.code, error.message)


def process_url(path, fileout, args):
    try:
        abraia.from_url(path).process(args).to_file(fileout)
        print('New image saved:', fileout)
    except APIError as error:
        print('Error', error.code, error.message)


def process_list(path):
    files, folders = abraia.list(path)
    txt = '\n'.join(['{:>28}  {}/'.format('', f['name']) for f in folders]) + '\n'
    txt += '\n'.join(['{}  {:>7}  {}'.format(f['date'], f['size'], f['name']) for f in files])
    txt += '\ntotal {}'.format(len(files))
    print(txt)


def process_upload(path):
    try:
        print(abraia.from_file(path))
    except APIError as error:
        print('Error', error.code, error.message)
        

def process_download(path):
    try:
        abraia.from_store(path).to_file(path)
    except APIError as error:
        print('Error', error.code, error.message)


def process_remove(path):
    print(abraia.from_store(path).remove())


def add_parser_info(subparser):
    parser_info = subparser.add_parser('info', help='show user account information')
    return parser_info


def add_parser_configure(subparser):
    parser_configure = subparser.add_parser('configure', help='configure the access keys')
    return parser_configure


def add_parser_optimize(subparser):
    parser_optimize = subparser.add_parser('optimize', help='optimize an image or a directory of images')
    parser_optimize.add_argument('--width', type=int, help='resize to specified width')
    parser_optimize.add_argument('--height', type=int, help='resize to specified height')
    parser_optimize.add_argument('--format', type=str, help='convert to specified image format. Allowed output extensions: %s' % str(config.IMAGE_EXTS))
    parser_optimize.add_argument('--action', type=str, help='apply the specified action')
    parser_optimize.add_argument('path', nargs='?', help='image path or directory to process')
    parser_optimize.add_argument('dest', nargs='?', help='destination directory or image path')
    return parser_optimize


def add_parser_list(subparser):
    parser_list = subparser.add_parser('list', help='list stored files')
    parser_list.add_argument('path', nargs='?', default='', help='folder path to list')
    return parser_list

def add_parser_upload(subparser):
    parser_download = subparser.add_parser('upload', help='upload a stored file')
    parser_download.add_argument('path', nargs='?', help='file path to upload')
    return parser_download

def add_parser_download(subparser):
    parser_download = subparser.add_parser('download', help='download a stored file')
    parser_download.add_argument('path', nargs='?', help='file path to download')
    return parser_download


def add_parser_remove(subparser):
    parser_remove = subparser.add_parser('remove', help='remove a stored file')
    parser_remove.add_argument('path', nargs='?', help='file path to remove')
    return parser_remove


def parse_input():
    parser = argparse.ArgumentParser(description='Abraia image optimization tool')
    parser.add_argument('-V', '--version', action='version', version='0.6.1')
    subparser = parser.add_subparsers(dest='command')
    parser_info = add_parser_info(subparser)
    parser_configure = add_parser_configure(subparser)
    parser_optimize = add_parser_optimize(subparser)
    parser_list = add_parser_list(subparser)
    parser_upload = add_parser_upload(subparser)
    parser_download = add_parser_download(subparser)
    parser_remove = add_parser_remove(subparser)
    args = vars(parser.parse_args())
    if args['command'] is None:
        parser.print_help()
        sys.exit()
    elif args['command'] == 'optimize':
        if args['path'] is None:
            parser_optimize.print_help()
            sys.exit()
    elif args['command'] == 'upload':
        if args['path'] is None:
            parser_upload.print_help()
            sys.exit()
    elif args['command'] == 'download':
        if args['path'] is None:
            parser_download.print_help()
            sys.exit()
    elif args['command'] == 'remove':
        if args['path'] is None:
            parser_remove.print_help()
            sys.exit()
    return args


def process_input(args):
    if args['command'] == 'info':
        process_info()
    if args['command'] == 'configure':
        process_configure()
    elif args['command'] == 'optimize':
        process_optimize(args)
    elif args['command'] == 'list':
        process_list(args.get('path'))
    elif args['command'] == 'upload':
        process_upload(args.get('path'))
    elif args['command'] == 'download':
        process_download(args.get('path'))
    elif args['command'] == 'remove':
        process_remove(args.get('path'))


if __name__ == "__main__":
    args = parse_input()
    process_input(args)
