#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
# -----------------------------------------------------------
# Filename      : gcollinder.py
# Description   : Converting a human ish string, in to a google calendar URL.
#                 Poorly recreating the "Create Event" that no longer exists ):
# Created By    : Bea Hughes
# Date Created  : 2020-02-24 22:02
#
# License       : MIT
# -----------------------------------------------------------

# have a python 3 like print() for stderr writing as a little treat
from __future__ import print_function

__author__ = "Bea Hughes"
__version__ = "0.2"

import re
import sys
import urllib
import webbrowser
from dateparser.search import search_dates
from datetime import datetime as dt
from datetime import timedelta


class Entry:

    DEFAULT_EVENT_DUR = timedelta(minutes=30)

    MIDNIGHT = dt.time(dt(1979, 1, 1, 0, 0))

    RE = re.compile(r"""
                    \b (?P<location>in \s+ .+) ($|\bat\b)
                    """, re.X)

    def __init__(self, raw):
        self.raw = str(raw)
        self.__parse__()

    def __parse__(self):

        event = self.raw

        self.dates = search_dates(event,
                                  languages=['en'],
                                  settings={'DATE_ORDER': 'DMY'})
        if self.dates is None:
            print("No dates found, boo", file=sys.stderr)
            sys.exit(10)

        event = ''.join({event.replace(str(atuple[0]), '')
                        for atuple in self.dates})
        event = re.sub(r"\s\s", " ", event)
        self.text = event

        # If we can grab a location (has 'in <location>' in it), then set the
        # location and remove that from the event text/title.
        self.location = ''
        r = self.RE.search(self.raw)
        if r:
            self.location = r.group('location')

    def generate_url(self):
        # URL format something like
        # http://www.google.com/calendar/event?ctext=+{query}+&action=TEMPLATE&pprop=HowCreated%3AQUICKA
        # Format is [event] at [time] on [date] in [location]

        # https://calendar.google.com/calendar/render?action=TEMPLATE&
        #  text=foo&
        #  dates=20170101T270000Z/20170101T280000Z&
        #  details=Describe your event.&
        #  location=Event Location&
        #  trp=true
        base = 'https://calendar.google.com/calendar/render'
        quer = {'action': 'TEMPLATE',
                'text': self.text,
                # 'dates': self.dates,  # this now comes from a function()
                'location': self.location,
                'trp': True}

        # go off and beat the date guessed in to the format we want.
        # returns a Dict of date/dates: <format o dates>
        x = self.fixate_dates()
        quer.update(x)

        # Python 2:
        self.uri = base + '?' + urllib.urlencode(quer)
        return self.uri

    # Actually open it in a web browser
    def open_url(self):
        self.generate_url()  # generate the URI in the first place.
        # print("opening " + str(self.uri))
        webbrowser.open(self.uri)

    # dateparser will return some date/times grabbed from the input. It will do
    # it's best to make sense. This is the function that does that. A lot of
    # gross magic happens here.
    # returns a Dict of date/dates: <format o dates>
    def fixate_dates(self):

        if len(self.dates) == 1:

            lone_date = self.dates[0][1]
            if dt.time(lone_date) == self.MIDNIGHT:
                # this blindly assumes I do nothing at midnight. I know.
                # all day event, just has the day.
                x = {'date': d(lone_date)}
            else:
                # regular event, put a finish time of whatever duration we set,
                # so it knows how long to make the event.
                d2 = lone_date + self.DEFAULT_EVENT_DUR
                x = {'dates': d(lone_date) + '/' + d(d2)}
        elif len(self.dates) == 2:
            # having two dates could mean it guessed at two, or there is a
            # start and a finish. Bleh.
            d1 = self.dates[0][1]
            d2 = self.dates[1][1]

            f = self.__fucky__(d1, d2)
            if f is not False:
                print('fudging dates a bunch.')
                fudge = f + self.DEFAULT_EVENT_DUR
                x = {'dates': d(f) + '/' + d(fudge)}

        return x

    # we don't necessarily know the order here, as it depends how dateparser
    # does, so it could be one way, it could be the other, hence this
    # abomination.
    def __fucky__(self, d1, d2):
        for x, y in {d1: d2, d2: d1}.items():
            if dt.time(x) == self.MIDNIGHT \
               and dt.date(y) == dt.date(dt.today()):
                # actually return a dt object with the date from x and the time
                # from y (the inverse of what we check for)
                return dt.combine(dt.date(x), dt.time(y))
        return False


# gross helper to return the time in the format gcal wants.
# make it 20170101T270000Z format. Kinda here so it can have a shorter name.
def d(a_date):
    return(a_date.strftime('%Y%m%dT%H%M%S%Z'))


def something():

    if len(sys.argv) < 2:
        line = sys.stdin.readline()
    else:
        line = ' '.join(sys.argv[1:])

    if not line:
        return

    e = Entry(line)

    # print(e.url())
    e.open_url()


if __name__ == "__main__":
    something()
