#!/usr/bin/env python
import sys
import os
from datetime import datetime
from datetime import timedelta
from sigtools import modifiers

from clize import run

import pandas as pd
import matplotlib.pyplot as plt

DATA_FILENAME = os.path.expanduser("~/.pomodoro")
weekmap = [
    "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday", "Sunday"
]
day_format = '"%A %d. %B %Y"'


def load():
    """
    Load a pomodoro stats file into pandas dataframe
    Each row is a pomodoro 'work' session.
    The 'rest' sessions are ignored.
    The columns are:
        - start : starting datetime
        - end : ending datetime
        - duration : duration in seconds
        - day : starting date (without time)


    Returns
    -------

    pandas DataFrame
    """
    data = pd.read_csv(DATA_FILENAME, parse_dates=["start"])
    data = (data.loc[data["work"] == "work"])
    data["day"] = data["start"]
    data["day"] = data["day"].apply(lambda x: x.date())
    return data


def load_duration_per_day(data):
    """
    Given a pandas dataframe `data` obtained with `load`,  this
    function returns a pandas series with the number of hours of
    pomodoros per day. Each element of the series corresponds to
    a day with its corresponding number of hours of pomodoros.

    Parameters
    ----------

    data : pandas DataFrame

    Returns
    -------

    pandas Series
    """
    duration_per_day = data.groupby("day").sum() / 60.
    duration_per_day.index = pd.to_datetime(duration_per_day.index)
    return duration_per_day


@modifiers.kwoargs('weekof')
def main(action='overall', weekof='today'):
    """
    action can be :

        overall : all pomodoros together in a plot.
        week : nb of hours per day for a specific week.
            it accepts as an option "weekof" to specify the week.
            weekof can be any day of the week you want to visualize
            formatted as a python date.
            Example: --weekof='2018-01-01' will correspond to the week
            which the first january 2018 belongs to.
        days : mean nb of hours per day, globally.
        thisweek : nb of hours per day this week.
        lastweek : nb of hours per day last week.
        stats : mean and standard deviation per day.
        weeks : nb of hours per week.
        today : nb hours today.
        yesterday : nb hours yesterday.

    Examples usage
    --------------

    > pomostat overall
    > pomostat thisweek
    > pomostat lastweek
    > pomostat week --weekof='today' # equivalent to pomostat thisweek
    > pomostat week --weekof='2018-01-01' # week of first january
    > pomostat yesterday
    """
    data = load()
    if action == "overall":
        duration_per_day = load_duration_per_day(data)
        duration_per_day['duration(hours)'] = duration_per_day['duration']
        duration_per_day.plot(y='duration(hours)', x_compat=True)
        plt.show()
    elif action == "days":
        D = data.copy()
        D = D.groupby(by="date").sum().reset_index()
        D["day"] = D["date"].map(lambda x: x.weekday())
        D["dayname"] = D["date"].map(lambda x: weekmap[x.weekday()])
        D = D.groupby(by="dayname")
        D = D.mean() / 60.
        D['duration(hours)'] = D['duration']
        D = D.reset_index()
        D['weekday'] = D['dayname'].map(lambda d: weekmap.index(d))
        D = D.sort_values(by='weekday')
        print(D)
        D = D.plot(
            kind="bar",
            title="hours per day",
            figsize=(8, 8),
            x="dayname", y="duration(hours)")
        plt.title("Per day hours")
        plt.show()
    elif action in ("week", "thisweek", "lastweek"):
        D = data.copy()
        D["day"] = D["start"].map(lambda x: x.weekday())
        D["dayname"] = D["start"].map(lambda x: weekmap[x.weekday()])

        if action == 'thisweek':
            weekof = 'today'
        elif action == 'lastweek':
            today = datetime.today()
            last_monday = (today - timedelta(days=today.weekday()))
            last_sunday = last_monday - timedelta(days=1)
            weekof = str(last_sunday)
        else:
            pass  # in that case just use weekof

        day_of_week = pd.to_datetime(pd.to_datetime(weekof).date())
        last_monday_of_week = (
            day_of_week - timedelta(days=day_of_week.weekday()))
        first_day_of_week = last_monday_of_week
        last_day_of_week = first_day_of_week + timedelta(days=7)
        D = D[D.start >= first_day_of_week]
        D = D[D.start < last_day_of_week]
        if len(D) == 0:
            print('The week from {} to {} has no recorded pomodoro '
                  'sessions.'.format(
                    first_day_of_week.date(),
                    last_day_of_week.date()))
            sys.exit(0)
        D = D.groupby(by=["day", "dayname"])
        D = D.sum() / 60.
        total_week_hours = D['duration'].sum()
        D['duration(hours)'] = D['duration']

        D = D.reset_index().plot(
            kind="bar",
            title="hours per day",
            figsize=(8, 8),
            x="dayname", y="duration(hours)")
        plt.title("Total in the week : {:.3f} hours. Week of {} to {}".format(
            total_week_hours,
            first_day_of_week.strftime(day_format),
            last_day_of_week.strftime(day_format),
        ))
        plt.show()
    elif action == "stats":
        per_day = (data.groupby(by="day")).sum() / 60.
        print("per day : {}+/-{}".format(per_day.values.mean(),
                                         per_day.values.std()))
    elif action == "weeks":
        def week(x):
            return x.isocalendar()[1]

        def year(x):
            return x.isocalendar()[0]

        data['week'] = data['day'].apply(week)
        data['year'] = data['day'].apply(year)
        data = data.groupby(('week', 'year')).sum() / 60
        data = data.reset_index()
        data = data.sort_values(by=['year', 'week'], ascending=[True, True])
        data['weekyear'] = data['week'] + \
            (data['year'] - data['year'].min()) * 52
        data['duration(hours)'] = data['duration']
        print(data)
        data.plot(title="hours per week", x='weekyear', y='duration(hours)')
        plt.axhline(y=data['duration'].max(), c='green', ls='dashed')
        plt.show()
    elif action == "today" or action == "yesterday":
        d = 1 if action == "yesterday" else 0
        day = datetime.today().date() - timedelta(d)
        next_day = day + timedelta(1)
        day = pd.to_datetime(day)
        next_day = pd.to_datetime(next_day)
        D = data[(data["start"] >= day) & (data["start"] < next_day)]
        print("{:.3f} h".format(D["duration"].sum() / 60.))
    else:
        print('Action not recognized. It should be : "overall" or '
              '"week" or "days" or "thisweek" or "lastweek" or'
              '"stats" or "weeks" or "today" or "yesterday".')
        sys.exit(1)


if __name__ == "__main__":
    run(main)
