from ..utils.rmf import ResolvedMediaFile
import threading
import inspect

class NotFound:
    def __init__(self) -> None:
        pass

    def grab(self, channel):
        return "Resolver Not Found", {}

class EmptyPD:
    def __init__(self) -> None:
        pass

class Resolver(object):
    """
    Used for communicating with plugins
    """

    def __init__(self, data_file, data_folder, server_port, progress_dialog) -> None:
        """
        args:
            data_file (str): Path where to place (where is located) data file
            data_folder (str): Path where addons can store custom data
            server_port (str): Port for locally hosted server
            progressDialog (class): Gives info about grabbing progress
        """
        self.data_file = data_file
        self.data_folder = data_folder
        self.server_port = server_port
        self.progress_dialog = progress_dialog()
        self.pd = self.progress_dialog
        self.falcon_proxy = False


    def _getSubclassesNames(self):
        """
        Get names of subclasses

        Use _getSubclasses() to get class objects
        """
        return [cls.__name__ for cls in Resolver.__subclasses__()]

    def _getSubclasses(self):
        """
        Get classes directly
        
        Use _getSubclassesNames() to get only names
        """
        return Resolver.__subclasses__()

    def _getSubclassByName(self, name):
        """
        Get only 1 subclass which matches the name

        returns object
        """

        if name not in self._getSubclassesNames(): return NotFound

        for klass in self._getSubclasses():
            if klass.__name__ == name:
                return klass
        return NotFound

    def preloadResolvers(self):
        """
        Preloading can speed up resolve/load times
        """

        for klass in self._getSubclasses():
            for functionName, function in inspect.getmembers(klass, predicate=inspect.isfunction):
                if functionName != "preload": continue
                
                c = klass()
                c.parent = self
                c.username = None
                c.password = None
                
                threading.Thread(target=c.preload).start()
                break


    def resolve(self, module, channel, username="", password=""):
        """
        Args:
            module (str): Plugin to use
            channel (str): Channel to grab
            username (str): Not required, some sources have defaults
            password (str): Not required, some sources have defaults

        Returns:
            rmf (ResolvedMediaFile): use .url or .headers to get data, .test() to test if stream works
        """

        c = self._getSubclassByName(module)()
        c.parent = self
        c.username = username
        c.password = password

        response = c.grab(channel)

        if isinstance(response, ResolvedMediaFile):
            return response

        return ResolvedMediaFile(
            url=response[0] if response[0] else "",
            headers=response[1] if response[1] else ""
        )


    def module_exists(self, module):
        resp = self._getSubclassByName(module)()

        if type(resp) == NotFound:
            return False
        return True
