#!/usr/bin/env python 3
# -*- coding: utf-8 -*-
"""Grit Task is a CLI task app using Click and Google Cloud Datastore.

Example:

    .. code-block:: Bash

       thtask tasks list

    .. code-block:: Bash

       thtask task create 'I am a new task with tags' -t new -t script -t code
"""

import datetime

import click

from google.cloud import datastore


def get_client():

    try:
        client = datastore.Client()
        return client
    except Exception as e:
        print('Grit Auth Error:\n')
        print('Run $ gcloud beta auth application-default login')
        print('Run $ gcloud auth login \n')
        print('{}\n'.format(e))


def task_format(task):
    """Formats tasks and nicely outputs to command line"""

    # Handles tags if tags are not present on task object.
    if task['tags'] == ['']:
        tag_list = ''
    else:
        tag_list = ''

        for tag in task['tags']:
            tag_list += '|{}'.format(tag)

        tag_list += '|'

    # Builds tag status for output
    if task['done']:
        status = 'done'
    else:
        status = task['created'].strftime('%m/%d %I:%M%p')

    formated_task = 'Status[{:-^13}] -{:<50} {:<35} ID:{:<20}'.format(
        status, task['description'], tag_list, task.key.id)

    # Tasks marked done, out put in red. Not yet done tasks are green.
    if task['done'] is True:
        click.secho(formated_task, fg='red')
    else:
        click.secho(formated_task, fg='green')


def get_task(ctx, param, value):
    """Retrieves task from the Datastore by task ID"""

    with get_client().transaction():
        key = get_client().key('Task', value)
        task = get_client().get(key)

        if not task:
            print('Task {} does not exist.'.format(value))
            ctx.exit()
        else:
            ctx.obj = task


@click.group()
@click.version_option()
def cli():
    """A command line task app using Google Datastore"""


@cli.group()
def tasks():
    """Manages all tasks"""


@tasks.command('list', short_help='Lists all tasks')
def list_tasks():
    """Lists all tasks in the Datastore

    Example:

        .. code-block:: Bash

           thtask tasks list
    """
    query = get_client().query(kind='Task')
    query.order = ['done']
    task_list = list(query.fetch())

    for task in task_list:
        task_format(task)


@tasks.command('tags', short_help='Lists all tags')
def list_tags():
    """Lists all unique tags

    Example:

        .. code-block:: Bash

           thtask tasks tags
    """
    # loads query object from client with kind of Task and projection of
    # tags.
    query = get_client().query(kind='Task')
    query.projection = ['tags']
    tags = []

    for task in query.fetch():
        tags.append(task['tags'])

    tag_set = {tag for tag in tags}
    tags = list(tag_set)
    tags.sort()
    click.secho('|' + '|'.join(tags) + '|', fg='green')


@tasks.command('sort', short_help='Sorts tasks on a tag')
@click.option('--tag', '-t', help='Enter tag name')
def sort_tasks(tag):
    """Sorts tasks on a specific tag

    Example:

        .. code-block:: Bash

           thtask tasks sort -t code
    """

    query = get_client().query(kind='Task')
    query.add_filter('tags', '=', tag.upper())
    query.order = ['done']
    task_list = list(query.fetch())

    for task in task_list:
        task_format(task)


@cli.group()
@click.pass_context
def task(ctx):
    """Manages individual tasks"""


@task.command('create', short_help='Creates new task')
@click.option('--description', '-d')
@click.option('--tags', '-t', multiple=True, help='Enter tag name')
def create_task(description, tags):
    """Creates a new task

    Example:

        .. code-block:: Bash

           thtask task create 'I am a new task' -t tag1 -t tag2 -t 'tag 3'

    .. note:: Creating a Task

       - The description argument must be in quotes

       - Mulitple tags may be entered each preceded by the -t flag

       - Tag names with spaces must be in quotes

    """

    if not tags:
        tags = ['']
    else:
        tags = [tag.upper() for tag in tags]

    key = get_client().key('Task')
    task = datastore.Entity(
        key, exclude_from_indexes=['description'])

    task.update({
        'created': datetime.datetime.now(),
        'description': description,
        'done': False,
        'tags': tags
    })
    get_client().put(task)
    task_format(task)


@task.command('update')
@click.option('--id', '-i', prompt=True, help='Enter task id', type=int,
              callback=get_task, expose_value=False)
@click.pass_obj
def update_task(task):
    """Updates a task

    Example:

        .. code-block:: Bash

           thtask task update -i <task id>

    .. note:: Update

       - Hit enter key to keep current value.

       - For tags, press space bar and return to delete the tag.

       - If no new tag needed, hit return.
    """

    # Prompt to update task description
    task['description'] = click.prompt(
        'Update description', default=task['description'])

    i = 0
    while i < len(task['tags']):

        # Loop through tags and prompt to update tag
        task['tags'][i] = click.prompt(
            'Update tag', default=task['tags'][i]).upper()

        # If tag is blank (Space entered) delete the tag
        if task['tags'][i] == ' ':
            task['tags'].pop(i)
            i -= 1
        i += 1

    # Add new tag if needed
    new_tag = click.prompt('Add new tag', default=' ')
    if new_tag is not ' ':
        task['tags'].append(new_tag.upper())

    # Update task in Datastore
    get_client().put(task)
    task_format(task)


@task.command('done', short_help='Mark task as done')
@click.option('--id', '-i', prompt=True, help='Enter task id', type=int,
              callback=get_task, expose_value=False)
@click.pass_obj
def done_task(task):
    """Updates task status to done by ID

    Example:

        .. code-block:: Bash

           thtask task -i <task_id> done

    .. note:: The Task ID is displayed when tasks are listed or sorted.
    """

    task['done'] = True
    get_client().put(task)
    task_format(task)


@task.command('delete', short_help='Deletes a task')
@click.option('--id', '-i', prompt=True, help='Enter task id', type=int,
              callback=get_task, expose_value=False)
@click.pass_obj
def delete_task(task):
    """Deletes a task by ID

    Example:

        .. code-block:: Bash

           thtask -i <task_id> task delete

    .. note:: The task ID is displayed when tasks are listed or sorted.
    """
    id = task.key.id
    key = task.key
    get_client().delete(key)
    click.secho(' Deleted task {} '.format(id), fg='black', bg='red')
