import functools
import os.path

from django.apps import apps
from django.apps.config import AppConfig
from django.template.loaders import filesystem

from ocyan.core.utils import unique_everseen

from ocyan.main.settings.base import _installed_apps as INSTALLED_APPS


@functools.lru_cache()
def get_app_extension_template_dirs(dirname):
    """
    Return an iterable of paths of directories to load app templates from.
    This version also adds any replaced apps and app extensions, in the
    correct order of priority.
    dirname is the name of the subdirectory containing templates inside
    installed applications.

    >>> slash = lambda x: "/".join(str(x).rsplit("/", maxsplit=3)[1:])
    >>> fuck_up_some_slashes = lambda templates: set([slash(x) for x in templates])

    >>> from django.template.utils import get_app_template_dirs

    >>> templates = get_app_template_dirs('templates')
    >>> old_app_loader_templates = fuck_up_some_slashes(templates)

    >>> templates2 = get_app_extension_template_dirs('templates')
    >>> new_app_loader_templates = fuck_up_some_slashes(templates2)

    >>> old_app_loader_templates.issubset(new_app_loader_templates)
    True
    """
    template_dirs = []

    app_name_table = {app_cfg.name: app_cfg for app_cfg in apps.get_app_configs()}
    for app_config in apps.get_app_configs():
        section = INSTALLED_APPS.section_for_app_extension(app_config.name)
        if section is not None:
            for app_ext in section.extensions_from_app_root(app_config.name):
                if app_ext in app_name_table:
                    ext_app_config = app_name_table[app_ext]
                else:
                    ext_app_config = AppConfig.create(app_ext)

                if not ext_app_config.path:
                    continue
                template_dir = os.path.join(ext_app_config.path, dirname)
                if os.path.isdir(template_dir):
                    template_dirs.append(template_dir)
        else:
            if not app_config.path:
                continue
            template_dir = os.path.join(app_config.path, dirname)
            if os.path.isdir(template_dir):
                template_dirs.append(template_dir)

    # Immutable return value because it will be cached and shared by callers.
    return tuple(unique_everseen(template_dirs))


class OcyanExtendedAppTemplateLoader(filesystem.Loader):
    def get_dirs(self):
        return get_app_extension_template_dirs("templates")
