#! /usr/bin/env python3.6
# coding: utf-8
import datetime as dt
import itertools
import time
from operator import attrgetter

import psycopg2
from slackclient import SlackClient

from gargbot_3000 import config, database_manager, droppics, task
from gargbot_3000.logger import log

mort_picurl = "https://pbs.twimg.com/media/DAgm_X3WsAAQRGo.jpg"


class Birthday:
    def __init__(self, nick, slack_id, date):
        self.nick = nick
        born_midnight_utc = dt.datetime.combine(date, dt.datetime.min.time())
        born_midnight_local = born_midnight_utc.astimezone(config.tz)
        born_morning_local = born_midnight_local.replace(hour=7)
        self.born = born_morning_local
        self.slack_id = slack_id

    def __repr__(self):
        return f"{self.nick}, {self.age} years. Next bday: {self.next_bday}"

    def seconds_to_bday(self):
        to_next_bday = self.next_bday - dt.datetime.now(config.tz)

        secs = to_next_bday.total_seconds()
        return secs if secs > 0 else 0

    @property
    def age(self):
        return dt.datetime.now(config.tz).year - self.born.year

    @property
    def next_bday(self):
        now = dt.datetime.now(config.tz)
        bday_thisyear = self.born.replace(year=now.year)
        bday_nextyear = self.born.replace(year=now.year + 1)
        next_bday = bday_thisyear if bday_thisyear > now else bday_nextyear
        return next_bday


def get_birthdays(db):
    with db.cursor() as cursor:
        sql_command = "SELECT slack_nick, slack_id, bday FROM user_ids"
        cursor.execute(sql_command)
        data = cursor.fetchall()
    birthdays = [
        Birthday(row["slack_nick"], row["slack_id"], row["bday"]) for row in data
    ]
    birthdays.sort(key=attrgetter("next_bday"))
    return birthdays


def get_sentence(db):
    with db.cursor() as cursor:
        sql_command = "SELECT sentence FROM congrats ORDER BY RANDOM() LIMIT 1"
        cursor.execute(sql_command)
        result = cursor.fetchone()
    sentence = result["sentence"]
    return sentence


def get_greeting(person, db, drop_pics):
    sentence = get_sentence(db)
    text = (
        f"Hurra! Vår felles venn <@{person.slack_id}> fyller {person.age} i dag!\n"
        f"{sentence}"
    )
    try:
        person_picurl, date, _ = drop_pics.get_pic(db, [person.nick])
    except psycopg2.OperationalError:
        db.ping(True)
        person_picurl, date, _ = drop_pics.get_pic(db, [person.nick])
    response = {
        "text": text,
        "blocks": [
            {"type": "section", "text": {"type": "mrkdwn", "text": text}},
            {"type": "image", "image_url": person_picurl, "alt_text": person_picurl},
            {"type": "image", "image_url": mort_picurl, "alt_text": mort_picurl},
        ],
    }

    return response


def handle_congrats(slack_client: SlackClient, drop_pics, db_connection):
    birthdays = get_birthdays(db_connection)
    db_connection.close()
    for birthday in itertools.cycle(birthdays):
        log.info(f"Next birthday: {birthday.nick}, at {birthday.next_bday}")
        try:
            time.sleep(birthday.seconds_to_bday())
        except OverflowError:
            log.info(
                "Too long sleep length for OS. "
                f"Restart before next birthday, at {birthday.next_bday}"
            )
            break
        db_connection = database_manager.connect_to_database()
        response = get_greeting(birthday, db_connection, drop_pics)
        task.send_response(slack_client, response=response, channel=config.main_channel)
        db_connection.close()


def main():
    db_connection = database_manager.connect_to_database()
    drop_pics = droppics.DropPics(db=db_connection)
    slack_client = SlackClient(config.slack_bot_user_token)
    connected = slack_client.rtm_connect()
    if not connected:
        raise Exception("Connection failed. Invalid Slack token or bot ID?")

    handle_congrats(slack_client, drop_pics, db_connection)

@@ -86,16 +86,35 @@
 rt time%0A
+import typing as t%0A
 from ope
@@ -154,16 +154,59 @@
 sycopg2%0A
+from psycopg2.extensions import connection%0A
 from sla
@@ -442,24 +442,29 @@
 _(self, nick
+: str
 , slack_id, 
@@ -461,18 +461,32 @@
 slack_id
-, 
+: str, date: dt.
 date):%0A 
@@ -918,32 +918,39 @@
 ds_to_bday(self)
+ -%3E int
 :%0A        to_nex
@@ -1018,16 +1018,20 @@
  secs = 
+int(
 to_next_
@@ -1050,16 +1050,17 @@
 econds()
+)
 %0A       
@@ -1119,24 +1119,31 @@
 ef age(self)
+ -%3E int
 :%0A        re
@@ -1230,24 +1230,39 @@
 t_bday(self)
+ -%3E dt.datetime
 :%0A        no
@@ -1533,17 +1533,49 @@
 hdays(db
-)
+: connection) -%3E t.List%5BBirthday%5D
 :%0A    wi
@@ -1937,17 +1937,36 @@
 tence(db
-)
+: connection) -%3E str
 :%0A    wi
@@ -2221,20 +2221,42 @@
 g(person
-, db
+: Birthday, db: connection
 , drop_p
@@ -2259,16 +2259,26 @@
 op_pics)
+ -%3E t.Dict
 :%0A    se
@@ -2991,32 +2991,37 @@
 handle_congrats(
+%0A    
 slack_client: Sl
@@ -3040,32 +3040,72 @@
 rop_pics
-, db_connection)
+: droppics.DropPics, db_connection: connection%0A) -%3E None
 :%0A    bi
@@ -3816,16 +3816,16 @@
 ose()%0A%0A%0A
-
 def main
@@ -3826,16 +3826,24 @@
 f main()
+ -%3E None
 :%0A    db

Add types to greetings