#!/usr/bin/env 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)
