#!/usr/bin/env python
"""
CLI utility for logging the time you spend on things.
    Usage: `logtime --help`
"""
from __future__ import print_function

from builtins import str
from builtins import range
from datetime import date, datetime, timedelta
import os
import re
import click
import logtime_cli.logfile_data as logfile_data
import logtime_cli.logfile_io as logfile_io
import logtime_cli.logtime_config as logtime_config


@click.group(context_settings=dict(help_option_names=['-h', '--help']))
def entry_point():
    """logtime"""


@entry_point.command()
@click.option('--previous', '-p', type=int, help='Use the logfile X days in the past.')
def calc(previous):
    """Print calculated time for the day.

    Records beginning in `*` are considered "non-work hours".
    """
    if previous:
        logdate = (date.today() - timedelta(days=previous))
    else:
        logdate = date.today()

    if not logfile_io.exists(logdate):
        print("No logfile exists for " + str(logdate) + ".")
        return

    log_data = logfile_io.load_logfile(logdate)

    all_hours = sum([x.duration() for x in log_data.entries])
    work_hours = sum([x.duration() for x in log_data.entries if x.task[:1] == '*'])
    non_work_hours = sum([x.duration() for x in log_data.entries if x.task[:1] != '*'])

    print(logdate)
    print("All Hours: " + str(all_hours))
    print("Non-Work Hours: " + str(work_hours))
    print("Work Hours: " + str(non_work_hours))


@entry_point.command()
@click.option('--previous', '-p', type=int, help='Use the logfile X days in the past.')
def count_tasks(previous):
    """Print number of tasks logged for the given day."""
    if previous:
        logdate = (date.today() - timedelta(days=previous))
    else:
        logdate = date.today()

    if not logfile_io.exists(logdate):
        print("No logfile exists for " + str(logdate) + ".")
        return

    log_data = logfile_io.load_logfile(logdate)

    print(len(log_data.entries))


@entry_point.command()
def list(): #pylint: disable=redefined-builtin
    """List existing logfiles, along with how many days back it is (for use with `-p`)"""
    log_file_directory = logtime_config.get_option('DEFAULT', 'logfile_directory')
    iso_date_regex = r'[0-9]{4}-[0-9]{2}-[0-9]{2}\.md'

    file_names = [f for f in os.listdir(log_file_directory)
                  if re.match(iso_date_regex, f)
                  and not os.path.isdir(os.path.join(log_file_directory, f))]

    for name in file_names:
        file_date = datetime.strptime(name, '%Y-%m-%d.md')

        delta = datetime.today() - file_date

        print('{date} - {days}'.format(days=delta.days, date=name))

@entry_point.command()
@click.option('--previous', '-p', type=int,
              help='Use the week X weeks in the past; Monday begins the week.')
def summarize_week(previous):
    """Print Summary section for every day of the chosen week."""
    if previous:
        logdate = (date.today() - timedelta(weeks=previous))
    else:
        logdate = date.today()

    first_day_delta = 0 - logdate.weekday() # 0 is Monday
    last_day_delta = 7 - logdate.weekday() # 7 is the number of weekdays

    week_range = range(first_day_delta, last_day_delta)

    # Center the list on this week; start on Monday
    weekdays = [(logdate + timedelta(days=x)) for x in week_range]

    for day in weekdays:
        if logfile_io.exists(day):
            log_data = logfile_io.load_logfile(day)
            notes = logfile_data.get_notes_data(log_data)
            notes_sections = notes.get_subsections()

            summaries = [x.full_text for x in notes_sections if x.name == 'Summary']
            if len(summaries) > 1:
                raise NotImplementedError(
                    'Found more than one Summary for {}. Combine them.'.format(day))
            if len(summaries) == 1:
                print('## {}'.format(day))
                print(summaries[0])
                print('')


def _get_sections_at_depth(notes_sections, current_depth, depth_to_search):
    """Only get sections at *exactly* the given depth_to_search"""
    sections_at_depth = []
    if current_depth == depth_to_search:
        sections_at_depth = notes_sections
    else:
        for section in notes_sections:
            subsections = section.get_subsections()
            sections_at_depth.extend(
                _get_sections_at_depth(subsections, current_depth+1, depth_to_search)
            )
    return sections_at_depth

def _get_sections_all_depths(notes_sections):
    """Get every single section, at any depth"""
    sections = notes_sections
    for section in notes_sections:
        subsections = section.get_subsections()
        sections.extend(
            _get_sections_all_depths(subsections)
        )
    return sections


@entry_point.command()
@click.argument('section_name')
@click.option('--depth', '-d', type=int,
              help='Depth of subsection to search.'
              ' Will only search this depth. Default 1.')
@click.option('--all-depths', '-a', is_flag=True,
              help='Indicates searching all depths at once.'
              ' Useful for finding sections at unknown depths.')
def section_report(section_name, depth, all_depths):
    """
    Find all instances of the given section_name at the given depth, for all logfiles.
    Print that section's contents.
    """
    if not depth:
        depth = 1

    log_file_directory = logtime_config.get_option('DEFAULT', 'logfile_directory')
    iso_date_regex = r'[0-9]{4}-[0-9]{2}-[0-9]{2}\.md'

    file_names = [f for f in os.listdir(log_file_directory)
                  if re.match(iso_date_regex, f)
                  and not os.path.isdir(os.path.join(log_file_directory, f))]

    for name in file_names:
        file_date = datetime.strptime(name, '%Y-%m-%d.md').date()
        log_data = logfile_io.load_logfile(file_date)
        notes = logfile_data.get_notes_data(log_data)
        notes_sections = notes.get_subsections()

        if all_depths:
            sections_to_search = _get_sections_all_depths(notes_sections)
        else:
            sections_to_search = _get_sections_at_depth(notes_sections, 1, depth)

        found_sections = [x.full_text for x in sections_to_search if x.name == section_name]

        if len(found_sections) > 1:
            raise NotImplementedError(
                'Found two or more Sections with that name for {}. Combine them.'.format(file_date))
        if len(found_sections) == 1:
            print('## {}'.format(file_date))
            print(found_sections[0])
            print('')


if __name__ == '__main__':
    entry_point() #pylint: disable=no-value-for-parameter
