import sys
import glob
import json
import inspect
import importlib

from aqbot.lib.plugins.info import PluginInfo
from aqbot.lib.plugins.plugin import PluginObject


class PluginManager(object):
    raw_log = None
    error_log = None

    path = ""
    module = ""

    info_objects = {}
    plugin_objects = {}

    def __init__(self, bot, path="./aqbot/plugins", module="plugins"):
        self.bot = bot
        self.command_manager = self.bot.command_manager
        self.messenger = self.bot.messenger

        self.raw_log = self.bot.raw_log
        self.error_log = self.bot.error_log
        sys.excepthook = self.error_log.exception

        self.module = module
        self.path = path
        self.raw_log.log("debug", __file__, "PluginManager started!")

    def scan(self):
        self.raw_log.log("debug", __file__, "Scanning plugin path...")
        self.info_objects = {}
        files = glob.glob("%s/conf/*.json" % self.path)

        if not files:
            self.error_log.log("error", __file__, "No plugins found!")
            return

        for f in files:
            try:
                with open(f) as c:
                    data = json.load(c)
                    name = data['name'].lower()
                    self.info_objects[name] = PluginInfo(data)
            except:
                self.error_log.log("error", __file__, "Uncaught Exception: %s!" % sys.exc_info()[0])

    def load_plugins(self, plugins):
        self.raw_log.log("debug", __file__, "Loading plugins...")

        for name in plugins:
            name = name.lower()

            if name not in self.info_objects:
                self.error_log.log("error", __file__, "Unknown plugin: %s" % name)
                continue
            else:
                self.load_plugin(name)

        self.raw_log.log("debug", __file__, "Plugins loaded!")

    def load_plugin(self, name):
        self.raw_log.log("debug", __file__, "Loading plugin: %s..." % name)
        name = name.lower()

        if name not in self.info_objects:
            self.error_log.log("error", __file__, "Plugin '%s' does not exist!" % name)
            return

        if self.plugin_loaded(name):
            self.raw_log.log("info", __file__, "Plugin '%s' is already loaded!" % name)
            return

        info = self.info_objects[name]
        try:
            module = info.get_module()
        except:
            if self.plugin_loaded(name):
                del self.plugin_objects[name]
            self.error_log.log("error", __file__, "Uncaught Exception: %s!" % sys.exc_info()[0])
            return

        try:
            obj = None
            module_obj = importlib.import_module(module)

            for name_, cls in inspect.getmembers(module_obj):
                if inspect.isclass(cls):
                    if cls.__module__ == module:
                        for parent in cls.__bases__:
                            if parent == PluginObject:
                                obj = cls(self, self.command_manager, self.bot.channel, self.messenger)
                                break
                        else:
                            continue
                        break

            if obj is None:
                if self.plugin_loaded(name):
                    del self.plugin_objects[name]
                return
            else:
                self.plugin_objects[name] = obj
        except ImportError:
            if self.plugin_loaded(name):
                del self.plugin_objects[name]
            self.error_log.log("error", __file__, "ImportError: %s!" % sys.exc_info()[0])
            return
        except:
            if self.plugin_loaded(name):
                del self.plugin_objects[name]
            self.error_log.log("error", __file__, "Uncaught Plugin Exception: %s!" % sys.exc_info()[0])
            return

        try:
            obj.add_vars(info)
            obj.setup()
        except:
            if self.plugin_loaded(name):
                del self.plugin_objects[name]
            self.error_log.log("error", __file__, "Uncaught Exception: %s!" % sys.exc_info()[0])
            return

        self.raw_log.log("info", __file__, "Plugin '%s' loaded!" % name)

    def unload_plugin(self, name):
        self.raw_log.log("info", __file__, "Unloading plugin: %s" % name)
        name = name.lower()
        if name not in self.plugin_objects:
            self.error_log.log("error", __file__, "Plugin '%s' does not exist!" % name)

        obj = self.plugin_objects[name]
        self.command_manager.remove(obj)

        try:
            obj.deactivate()
        except:
            self.error_log.log("error", __file__, "Uncaught Exception: %s!" % sys.exc_info()[0])
            return

        del self.plugin_objects[name]
        self.raw_log.log("info", __file__, "Plugin '%s' unloaded!" % name)
        return True

    def reload_plugin(self, name):
        self.raw_log.log("info", __file__, "Reloading plugin: %s" % name)
        name = name.lower()
        if self.plugin_loaded(name):
            self.unload_plugin(name)
        return self.load_plugin(name)

    def get_plugin_info(self, name):
        self.raw_log.log("info", __file__, "Getting info for plugin: %s" % name)
        name = name.lower()
        if name in self.info_objects:
            return self.info_objects[name]
        return False

    def plugin_loaded(self, name):
        name = name.lower()
        return name in self.plugin_objects

