import json

from django.apps import apps as django_apps
from django.contrib.auth.mixins import UserPassesTestMixin
from django.http import JsonResponse
from django.views import View
from django.shortcuts import render, redirect

from .inspector import get_app_models, get_diagram_data
from .models import DiagramPreferences, _default_excluded_apps


class _StaffRequired(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.is_active and self.request.user.is_staff


def _get_prefs(user):
    try:
        p = user.lumen_preferences
        return {'selected_apps': p.selected_apps, 'excluded_apps': p.excluded_apps, 'routing_style': p.routing_style, 'show_only_managed': p.show_only_managed}
    except DiagramPreferences.DoesNotExist:
        return {'selected_apps': [], 'excluded_apps': _default_excluded_apps(), 'routing_style': 'curved', 'show_only_managed': False}


class DiagramView(_StaffRequired, View):
    def get(self, request):
        prefs = _get_prefs(request.user)
        models = get_app_models(excluded=prefs['excluded_apps'])
        data = get_diagram_data(models)
        return render(request, 'django_lumen/diagram.html', {
            'diagram_data': json.dumps(data),
            'prefs': json.dumps(prefs),
        })


class SavePreferencesView(_StaffRequired, View):
    def post(self, request):
        data = json.loads(request.body)
        DiagramPreferences.objects.update_or_create(
            user=request.user,
            defaults={
                'selected_apps': data.get('selected_apps', []),
                'excluded_apps': data.get('excluded_apps', []),
                'routing_style': data.get('routing_style', 'curved'),
                'show_only_managed': data.get('show_only_managed', False),
            },
        )
        return JsonResponse({'ok': True})


class ExcludedAppsView(_StaffRequired, View):
    def _all_app_labels(self):
        # All app labels from the registry, including system apps.
        return sorted({m._meta.app_label for m in django_apps.get_models()})

    def get(self, request):
        prefs = _get_prefs(request.user)
        return render(request, 'django_lumen/excluded_apps.html', {
            'all_apps': self._all_app_labels(),
            'excluded_apps': prefs['excluded_apps'],
        })

    def post(self, request):
        excluded = request.POST.getlist('excluded_apps')
        valid = set(self._all_app_labels())
        excluded = [a for a in excluded if a in valid]
        DiagramPreferences.objects.update_or_create(
            user=request.user,
            defaults={'excluded_apps': excluded},
        )
        return redirect('django-lumen-diagram')


class HelpView(_StaffRequired, View):
    def get(self, request):
        return render(request, 'django_lumen/help.html')
