import os
import re
import sys
import time
import logging
import telegram
import yaml
import threading

from urllib.error import URLError
from lytebot import config, config_dir
from lytebot.errors import CommandError

class LyteBot:
    paths = {
        'ignored': os.path.join(config_dir, 'ignored.yml'),
        'disabled': os.path.join(config_dir, 'disabled.yml'),
        'blacklisted': os.path.join(config_dir, 'blacklisted.yml'),
    }

    def __init__(self):
        '''Initialize bot'''
        self.prefix = '/'
        self.ignored = {}
        self.commands = {}
        self.disabled = []
        self.previous = {}
        self.blacklisted = []
        self._bot = telegram.Bot(token=config['telegram']['token'])
        # Disable Telegram API's logger to prevent spam
        self._bot.logger.disabled = True

        for n, f in self.paths.items():
            try:
                with open(f, 'r') as f:
                    setattr(self, n, yaml.load(f.read()))
            except FileNotFoundError:
                pass
            except Exception as e:
                logging.warning('Couldn\'t load {} data: {}'.format(n, e))
            else:
                logging.info('Loaded {} data'.format(n))

    def _set_previous(self, func, args):
        '''
        Save previous command per chat

        :param func: Command function
        :param args: Arguments given to command
        '''
        self.previous[args.chat_id] = {'func': func, 'args': args}

    def _handle_msg(self, update):
        '''
        Handles all messages sent in all chats (that the bot can see)

        :param update: Object with chat info
        '''
        # Ignore stickers, pictures and other non-text messages
        if not update['message'] or not update.message['text']:
            return

        # Is the user who sent the message ignored?
        if update.message.chat_id in self.ignored and \
           update.message.from_user.username in self.ignored[update.message.chat_id]:
            return

        message = update.message.text[1::]
        prefix = update.message.text[0]
        command = self.get_command(message)
        user = update.message.from_user.username or update.message.from_user.first_name

        if command and prefix == self.prefix and not self._is_disabled(command):
            # Check if the user is an owner if he calls an admin command
            if command['admin'] and update.message.from_user.username not in config['telegram']['owners']:
                text = '@{} You can\'t do that!'.format(user)
            else:
                text = command['func'](update.message, user)

            t = threading.Thread(target=self._bot.sendMessage, kwargs={
                'chat_id': update.message.chat_id,
                'text': text
            })
            t.start()

            self._last_id = update.update_id + 1

            if not message.startswith('!!'):
                self._set_previous(command['func'], update.message)

    def is_command(self, command):
        '''
        Check if a command exists

        :param command: Name to check
        :rtype: bool
        '''
        return command['func'].__name__ in self.commands

    def blacklist(self, sub):
        '''
        Blacklist a sub from the /r command

        :param sub: Subreddit to blacklist
        '''
        if sub not in self.blacklisted:
            self.blacklisted.append(sub.lower())
            self.save_data(self.paths['blacklisted'], self.blacklisted)

    def whitelist(self, sub):
        '''
        Whitelist a sub from the /r command

        :param sub: Subreddit to whitelist
        '''
        try:
            self.blacklisted.remove(sub.lower())
        except ValueError:
            return

        self.save_data(self.paths['blacklisted'], self.blacklisted)

    def disable(self, command):
        '''
        Disables a command in _all_ chats