#!/usr/bin/env python

import asyncio
import email
import pathlib
import sys
import logging

from os import path, listdir
from email.header import decode_header, make_header
from nio import (AsyncClient, Api, ClientConfig, RoomSendError)
from inotify_simple import INotify, flags


def decode(header):
    return make_header(decode_header(header))

class Client(AsyncClient):

    def send_message(self, From, Subject):
        return self.room_send(
            room_id=self.room,
            message_type="m.room.message",
            content={
                "msgtype": "m.text",
                "body": "From:\t%s\nSubject:\t%s" % (decode(From), decode(Subject))
                }
            )

    async def process_message(self, name):
        message_path = pathlib.Path(path.abspath(path.join(self.maildir, name)))
        message = email.message_from_file(open(message_path, 'r'))
        # send message
        logging.info('Sending %s', message_path)
        response = await self.send_message(message['from'], message['subject'])
        if response is not RoomSendError:
            # delete message
            logging.info('Removing message at: %s', message_path)
            message_path.unlink()
        else:
            logging.error('Failed to send a message: %s', message_path)

    # TODO implement retry for old mails
    async def process_queued(self):
        for name in listdir(self.maildir):
            await self.process_message(name)

    async def run(self, password=None, token=None):
        if token is None:
            response = await self.login(password, device_name = self.device)
            print("Access Token is", response.access_token)
        else:
            self.access_token = token

        await self.process_queued()

        while True:
            for event in self.notify.read():
                (_, _, _, name) = event
                if flags.CREATE in flags.from_mask(event.mask):
                    await self.process_message(name)

    async def shutdown(sig, loop):
        print('Shutting down')
        await self.close()

    def __init__(self, homeserver, user, device, room, maildir):
        super().__init__(homeserver, user)
        self.device = device
        self.room = room
        self.notify = INotify()
        self.maildir = maildir
        watch_flags = flags.CREATE
        wd = self.notify.add_watch(maildir, watch_flags)


def main():
    homeserver = sys.argv[1]
    username = sys.argv[2]
    device = sys.argv[3]
    room = sys.argv[4]
    maildir = sys.argv[5]
    if len(sys.argv) > 6:
        tokenfile = sys.argv[6]
    else:
        tokenfile = "apitoken.txt"

    client = Client(homeserver, username, device, room, maildir)

    loop = asyncio.get_event_loop()

    try:
        password = None
        token = None
        if path.isfile(tokenfile):
            with open(tokenfile) as f:
                token = f.readlines()[0].strip('\n')
        else:
            password = input('Could not find file for API-token. Please specify password.\nPassword: ')
        loop.run_until_complete(client.run(password = password, token = token))
    except KeyboardInterrupt:
        client.shutdown()
    finally:
        loop.close()


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    main()
