from collections import OrderedDict

from django.apps import apps
from django.conf import settings
from django.shortcuts import render
from django.urls.exceptions import NoReverseMatch
from django.utils.module_loading import import_string
from django.views.generic import View
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework.views import APIView


class InstalledPluginsAdminView(View):
    """
    Admin view for listing all installed plugins
    """
    def get(self, request):
        plugins = [apps.get_app_config(plugin) for plugin in settings.PLUGINS]
        return render(request, 'extras/admin/plugins_list.html', {
            'plugins': plugins,
        })


class InstalledPluginsAPIView(APIView):
    """
    API view for listing all installed plugins
    """
    permission_classes = [permissions.IsAdminUser]
    _ignore_model_permissions = True
    exclude_from_schema = True
    swagger_schema = None

    def get_view_name(self):
        return "Installed Plugins"

    @staticmethod
    def _get_plugin_data(plugin_app_config):
        return {
            'name': plugin_app_config.verbose_name,
            'package': plugin_app_config.name,
            'author': plugin_app_config.author,
            'author_email': plugin_app_config.author_email,
            'description': plugin_app_config.description,
            'verison': plugin_app_config.version
        }

    def get(self, request, format=None):
        return Response([self._get_plugin_data(apps.get_app_config(plugin)) for plugin in settings.PLUGINS])


class PluginsAPIRootView(APIView):
    _ignore_model_permissions = True
    exclude_from_schema = True
    swagger_schema = None

    def get_view_name(self):
        return "Plugins"

    @staticmethod
    def _get_plugin_entry(plugin, app_config, request, format):
        try:
            api_app_name = import_string(f"{plugin}.api.urls.app_name")
        except (ImportError, ModuleNotFoundError):
            # Plugin does not expose an API
            return None

        try:
            entry = (getattr(app_config, 'base_url', app_config.label), reverse(
                f"plugins-api:{api_app_name}:api-root",
                request=request,
                format=format
            ))
        except NoReverseMatch:
            # The plugin does not include an api-root
            entry = None

        return entry

    def get(self, request, format=None):

        entries = []
        for plugin in settings.PLUGINS:
            app_config = apps.get_app_config(plugin)
            entry = self._get_plugin_entry(plugin, app_config, request, format)
            if entry is not None:
                entries.append(entry)

        return Response(OrderedDict((
            ('installed-plugins', reverse('plugins-api:plugins-list', request=request, format=format)),
            *entries
        )))
