#!/usr/bin/env python3

import re, json
from os import path
from datetime import datetime, timedelta
from functools import lru_cache

import httplib2
import oauth2client
import apiclient
import dateutil.parser
from dateutil.tz import tzlocal
import requests

from ..utilities import BasePlugin
from ..utilities import clockify

CALENDAR_ID = "uc21b9q2nr2ggquc3c6ahdgeo4@group.calendar.google.com" # calendar ID for W A T E R L O O B O Y S
SAVED_OAUTH_CREDENTIALS_FILE = path.join(path.dirname(path.realpath(__file__)), "oauth_credentials.json") # OAuth credentials, generated by `src/plugins/events/generate_oauth_credentials.py`

class EventsPlugin(BasePlugin):
    """
    Event calendar listing plugin for Botty.

    Example invocations:

        #general    | Me: sup botty
        #general    | Botty: :timer_clock: *EVENTS IN THE NEXT 7 DAYS* :timer_clock:
        
        • [HAPPENING NOW] *Tech Talk: Defrobnicating The Gluon Manifold At Scale* _from_ :clock4: 16:00 _to_ :clock430: 16:30 _on_ :date: 2015-10-25 (Sunday) (http://tinyurl.com/usnrisy)
        
        • *Info Session: Oxygen - The New Killer App?* _from_ :clock10: 22:00 _to_ :clock1130: 23:30 _on_ :date: 2015-10-26 (Monday) (http://tinyurl.com/xmentkx)
        
        • *Bloodmoon: The Bloodmoon Rises* _from_ :date: 17:30 2015-10-27 (Tuesday) _to_ :date: 02:30 2015-10-28 (Wednesday) (http://tinyurl.com/gydyusw)
        
        • *Wednesday Evening Grassroots Blues* _from_ :clock7: 19:00 _to_ :clock11: 23:00 _on_ :date: 2015-10-28 (Wednesday) (http://tinyurl.com/trcbvfa)
        
        • *Movie Night: Gun Woman Reloaded* _from_ :date: 19:00 2015-10-28 (Wednesday) _to_ :date: 00:30 2015-10-29 (Thursday) (http://tinyurl.com/sdfklea)
    """
    def __init__(self, bot):
        super().__init__(bot)

    @lru_cache() # cache recently used results to speed up repeated calls with the same parameters
    def shorten_url(self, url):
        request = requests.get("http://tinyurl.com/api-create.php", params={"url": url})
        request.raise_for_status()
        return request.text

    def on_message(self, m):
        if not m.is_user_text_message: return False
        match = re.search(r"\b(?:sup\s+botty|wassup\s+botty|wh?at['\u2019]?s\s+(?:up|good)\s+botty|botty\s+wassup|botty\s+what['\u2019]s\s+(?:up|good)|what\s+are\s+the\s+haps)\b", m.text, re.IGNORECASE)
        if not match: return False

        # obtain Google Calendar service
        store = oauth2client.file.Storage(SAVED_OAUTH_CREDENTIALS_FILE)
        credentials = store.get()

        # fail gracefully if user has not configured this plugin yet
        if not credentials or credentials.invalid:
            self.respond_raw("oops, I can't find any valid OAuth credentials in `oauth_credentials.json` :( try `python3 src/plugins/events/generate_oauth_credentials.py`")
            return True

        # set up calendar service client
        authorized_http = credentials.authorize(httplib2.Http())
        calendar_service = apiclient.discovery.build("calendar", "v3", http=authorized_http)

        # obtain calendar events
        start_timestamp = datetime.utcnow().isoformat() + "Z" # reference date for events - all events ending before this are excluded from the results
        eventsResult = calendar_service.events().list(
            calendarId = CALENDAR_ID,
            timeMin = start_timestamp,
            maxResults = 30,
            singleEvents = True,
            orderBy = "startTime"
        ).execute()
        events = eventsResult.get("items", [])

        now = datetime.now()
        latest_event_cutoff = now + timedelta(days=7)
        result = []
        for event in events:
            if "dateTime" in event["start"]:
                start = dateutil.parser.parse(event["start"]["dateTime"]).astimezone(tzlocal()).replace(tzinfo=None) # start time in local time
            else:
                start = dateutil.parser.parse(event["start"]["date"])
            if "dateTime" in event["end"]:
                end = dateutil.parser.parse(event["end"]["dateTime"]).astimezone(tzlocal()).replace(tzinfo=None) # end time in local time
            else:
                end = dateutil.parser.parse(event["end"]["date"])
            if start > latest_event_cutoff:
                break
            summary = self.text_to_sendable_text(event["summary"])
            url = self.shorten_url(event["htmlLink"])
            if start.date() == end.date():
                result.append("\u2022 {}*{}* _from_ :{}: {} _to_ :{}: {} _on_ :date: {} ({})".format(
                    "[HAPPENING NOW] " if start <= now < end else "",
                    summary,
                    clockify(start), start.strftime("%H:%M"),
                    clockify(start), end.strftime("%H:%M"),
                    start.strftime("%Y-%m-%d (%A)"),
                    url
                ))
            else:
                result.append("\u2022 {}*{}* _from_ :date: {} _to_ :date: {} ({})".format(
                    "[HAPPENING NOW] " if start <= now < end else "",
                    summary,
                    start.strftime("%H:%M %Y-%m-%d (%A)"),
                    end.strftime("%H:%M %Y-%m-%d (%A)"),
                    url
                ))
        self.respond(":timer_clock: *EVENTS IN THE NEXT 7 DAYS* :timer_clock:\n\n{}".format("\n\n".join(result)))

        return True
