#!/usr/bin/env python
from __future__ import print_function
from __future__ import division
from builtins import input

import os
import sys
import json
import click
import shutil
from glob import glob
from tqdm import tqdm

try:
    from urllib.parse import urlparse
except ImportError:
    from urlparse import urlparse

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


abraia = Abraia(folder='batch/')


def is_url(url):
    res = urlparse(url)
    if res.scheme and res.netloc:
        return True
    return False


def echo_error(error):
    click.echo('[' + click.style('Error {}'.format(error.code),
                                 fg='red', bold=True) + '] {}'.format(error.message))


def input_files(src):
    if isinstance(src, str) and src.startswith('http'):
        return [src]
    src = os.path.join(src, '**/*') if os.path.isdir(src) else src
    return glob(src, recursive=True)


@click.group('abraia')
@click.version_option('0.6.6')
def cli():
    """Abraia CLI tool"""
    pass


@cli.command()
def configure():
    """Configure the abraia api key"""
    try:
        click.echo('Configure your api key [' + click.style(
            'https://abraia.me/console/settings', fg='green') + ']\n')
        abraia_key = config.load_key()
        abraia_key = click.prompt('Abraia Key', default=abraia_key)
        config.save_key(abraia_key)
    except:
        pass


@cli.command()
def info():
    """Show user account information"""
    click.echo('abraia, version 0.6.6\n')
    try:
        user = abraia.load_user()
        output = 'Name: {}\n'.format(user.get('name'))
        output += 'Email: {}\n'.format(user.get('email'))
        output += 'Credits: {}'.format(user.get('credits'))
        click.echo(output)
    except APIError as error:
        echo_error(error)


@cli.command()
@click.option('--width', help='Resize to specified width', type=int)
@click.option('--height', help='Resize to specified height', type=int)
@click.option('--format', help='Convert to specified image format', type=click.Choice(['jpeg', 'png', 'webp']))
@click.option('--action', help='Apply an action template', type=click.Path())
@click.argument('src')
@click.argument('dest', required=False)
def optimize(src, dest, width, height, format, action):
    """Optimize an image or set of images"""
    try:
        args = {'width': width, 'height': height, 'format': format, 'action': action}
        filenames = input_files(src)
        dirname = src.rstrip('/').rstrip('\\') if os.path.isdir(src) else None
        for filename in tqdm(filenames, unit='file'):
            if filename.startswith('http'):
                path, name = '', os.path.basename(filename)
            else:
                path, name = os.path.split(filename)
            nam, ext = name.split('.')
            oext = format if format is not None else ext
            fileout = dest if dest else 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 ext.lower() in config.MIME_TYPES.keys():
                if filename.startswith('http'):
                    abraia.from_url(filename).process(args).to_file(fileout)
                else:
                    abraia.from_file(filename).process(args).to_file(fileout)
            else:
                shutil.copy2(filename, fileout)
    except APIError as error:
        echo_error(error)


@cli.command()
@click.option('--remove', help='Remove file metadata', is_flag=True)
@click.argument('src')
def metadata(src, remove):
    """Load file metadata"""
    try:
        path = abraia.userid + '/' + abraia.folder
        resp = abraia.upload_file(src, path)
        if remove:
            print('remove', remove)
            print(abraia.remove_metadata(resp['source']))
            buffer = abraia.download_file(resp['source'])
            with open(src+'.output', 'wb') as f:
                f.write(buffer.getvalue())
        else:
            meta = abraia.load_metadata(resp['source'])
            click.echo(json.dumps(meta, indent=2))
    except APIError as error:
        echo_error(error)


@cli.command()
@click.option('--labels', 'mode', flag_value='labels', default=True, help='Detect image labels')
@click.option('--faces', 'mode', flag_value='faces', help='Detect image faces')
@click.option('--text', 'mode', flag_value='text', help='Detect image text')
@click.argument('src')
def detect(src, mode):
    """Detect image data"""
    try:
        path = abraia.userid + '/' + abraia.folder
        resp = abraia.upload_file(src, path)
        labels = abraia.detect_labels(resp['source'])
        click.echo(json.dumps(labels, indent=2))
    except APIError as error:
        echo_error(error)


@cli.command()
@click.argument('path', required=False)
def list(path):
    """List the files in abraia"""
    try:
        path = path if path else ''
        files, folders = abraia.list(path)
        output = '\n'.join(['{:>28}  {}/'.format('', click.style(f['name'], fg='blue', bold=True)) for f in folders]) + '\n'
        output += '\n'.join(['{}  {:>7}  {}'.format(f['date'], f['size'], f['name']) for f in files])
        output += '\ntotal {}'.format(len(files))
        click.echo(output)
    except APIError as error:
        echo_error(error)


@cli.command()
@click.argument('src', type=click.Path())
# @click.argument('dest', required=False)
def upload(src):
    """Upload a file to abraia"""
    try:
        with click.progressbar(input_files(src)) as files:
            for file in files:
                click.echo(abraia.upload(file, abraia.folder))
    except APIError as error:
        echo_error(error)


@cli.command()
@click.argument('path')
def download(path):
    """Download a file from abraia"""
    try:
        with click.progressbar(abraia.list(path)[0]) as files:
            for file in files:
                dest = os.path.basename(file['path'])
                click.echo(abraia.download(file['path'], dest))
    except APIError as error:
        echo_error(error)


@cli.command()
@click.argument('path')
@click.confirmation_option(prompt='Are you sure you want to remove the file?')
def remove(path):
    """Remove a file from abraia"""
    try:
        click.echo(abraia.remove(path))
    except APIError as error:
        echo_error(error)


if __name__ == '__main__':
    if not abraia.userid:
        configure()
    else:
        cli()
