#!/usr/bin/env python3

import pytoml as toml
import mastodon
import os
import pickle
import re
import time
import trigger
import logging
import sendmail

logger = logging.getLogger(__name__)


class RetootBot(object):
    def __init__(self, config, trigger):
        self.config = config
        self.trigger = trigger
        self.client_id = self.register()
        self.m = self.login()

        # load state
        try:
            with open('seen_toots.pickle', 'rb') as f:
                self.seen_toots = pickle.load(f)
        except IOError:
            self.seen_toots = set()

    def register(self):
        client_id = os.path.join(
            'appkeys',
            self.config['mapp']['name'] +
            '@' + self.config['muser']['server']
        )

        if not os.path.isfile(client_id):
            mastodon.Mastodon.create_app(
                self.config['mapp']['name'],
                api_base_url=self.config['muser']['server'],
                to_file=client_id
            )
        return client_id

    def login(self):
        m = mastodon.Mastodon(
            client_id=self.client_id,
            api_base_url=self.config['muser']['server']
        )
        m.log_in(
            self.config['muser']['email'],
            self.config['muser']['password']
        )
        return m

    def retoot(self, toots=()):
        # toot external provided messages
        for toot in toots:
            self.m.toot(toot)

        # boost mentions
        retoots = []
        for notification in self.m.notifications():
            if (notification['type'] == 'mention'
                    and notification['status']['id'] not in self.seen_toots):
                self.seen_toots.add(notification['status']['id'])
                text_content = re.sub(r'<[^>]*>', '',
                                      notification['status']['content'])
                if not self.trigger.is_ok(text_content):
                    continue
                logger.info('Boosting toot from %s: %s' % (
                    notification['status']['account']['acct'],
                    notification['status']['content']))
                self.m.status_reblog(notification['status']['id'])
                retoots.append('%s: %s' % (
                    notification['status']['account']['acct'],
                    re.sub(r'@\S*', '', text_content)))
        # If the Mastodon instance returns interesting Errors, add them here:

        # save state
        with os.fdopen(os.open('seen_toots.pickle.part', os.O_WRONLY | os.O_EXCL | os.O_CREAT), 'wb') as f:
            pickle.dump(self.seen_toots, f)
        os.rename('seen_toots.pickle.part', 'seen_toots.pickle')

        # return mentions for mirroring
        return retoots


if __name__ == '__main__':
    # read config in TOML format (https://github.com/toml-lang/toml#toml)
    with open('config.toml') as configfile:
        config = toml.load(configfile)

    fh = logging.FileHandler(config['logging']['logpath'])
    fh.setLevel(logging.DEBUG)
    logger.addHandler(fh)

    trigger = trigger.Trigger(config)
    bot = RetootBot(config, trigger)

    try:
        while True:
            bot.retoot()
            time.sleep(1)
    except KeyboardInterrupt:
            print("Good bye. Remember to restart the bot!")
    except:
        logger.error('Shutdown', exc_info=True)
        try:
            mailer = sendmail.Mailer(config)
            mailer.send('', config['mail']['contact'],
                        'Ticketfrei Crash Report',
                        attachment=config['logging']['logpath'])
        except:
            logger.error('Mail sending failed', exc_info=True)