#!/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.8.7')
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.8.7\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('--mode', help='Select the resize mode', type=click.Choice(['pad', 'crop', 'thumb']))
@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 convert(src, dest, width, height, mode, format, action):
    """Convert an image or set of images"""
    try:
        args = {'width': width, 'height': height, 'mode': mode, 'format': format, 'action': action, 'quality': 'auto'}
        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(urlparse(filename).path) or 'screenshot.png'
            else:
                path, name = os.path.split(filename)
            nam, ext = os.path.splitext(name)
            oext = format if format is not None else (ext and ext[1:])
            dest = 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))
                dest = os.path.join(dirname + '_o', relpath, nam + '.' + oext)
            if filename.startswith('http'):
                path = filename
                args['url'] = filename
            else:
                path = abraia.upload_file(filename)
            abraia.transform_image(path, dest, args)
    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 and remove file metadata"""
    try:
        path = abraia.userid + '/' + abraia.folder
        path = abraia.upload_file(src, path)
        if remove:
            print('remove', remove)
            print(abraia.remove_metadata(path))
            buffer = abraia.download_file(path)
            with open(src+'.output', 'wb') as f:
                f.write(buffer.getvalue())
        else:
            meta = abraia.load_metadata(path)
            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.upload_file(src, abraia.folder)
        if mode == 'labels':
            labels = abraia.detect_labels(path)
            click.echo(labels)
        if mode == 'text':
            text = abraia.capture_text(path)
            click.echo('\n'.join(text))
        if mode == 'faces':
            faces = abraia.detect_faces(path)
            click.echo(json.dumps(faces, 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_files(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('path', 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(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_files(path)[0]) as files:
            for file in files:
                path, dest = file['path'], os.path.basename(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_file(path))
    except APIError as error:
        echo_error(error)


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