from django.contrib import admin
from django.contrib.admin import ModelAdmin, StackedInline
from tenants.access import can_pick_tenant, filter_for_user, get_tenant_accessor
from tenants.forms import TenantModelForm

class GetQuerySetMixin:

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if can_pick_tenant(request.user):
            return qs
        return filter_for_user(self.model, request.user)

class TenantModelAdmin(GetQuerySetMixin, ModelAdmin):

    form = TenantModelForm

    def get_form(self, request, obj=None, change=False, **kwargs):
        form = super().get_form(request, obj, change, **kwargs)
        form.user = request.user
        return form

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if not can_pick_tenant(request.user):
            tenant_model = db_field.related_model
            kwargs['queryset'] = filter_for_user(tenant_model, request.user)
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

    def get_exclude(self, request, obj=None):
        result = super().get_exclude(request, obj)
        if not can_pick_tenant(request.user):
            result = list(result or []) + ['tenant']
        return result

    def get_list_display(self, request):
        result = list(super().get_list_display(request))
        if can_pick_tenant(request.user):
            tenant_accessor = get_tenant_accessor(self.model)
            # Django doesn't support transitive relations in list_display:
            if '__' not in tenant_accessor:
                field = self.model._meta.get_field('tenant')
                if field.many_to_many:
                    @admin.display(description='tenant')
                    def get_tenant(obj):
                        accessor_name = field.get_accessor_name()
                        return ', '.join(
                            str(t) for t in getattr(obj, accessor_name).all()
                        )
                    result = [get_tenant] + result
                else:
                    result = [tenant_accessor] + result
        return result

    def get_list_display_links(self, request, list_display):
        return self.get_list_display(request)

    def get_list_filter(self, request):
        result = list(super().get_list_filter(request))
        if can_pick_tenant(request.user):
            result = [get_tenant_accessor(self.model)] + result
        return result

    def lookup_allowed(self, lookup, value):
        # Allow filtering by tenant for models whose tenant field is transitive.
        # For example: Version -> Package -> Tenant. As a superuser, we want to
        # be able to filter versions by tenant. Without the following code, we
        # would get a `DisallowedModelAdminLookup` when trying to do this.
        tenant_accessor = get_tenant_accessor(self.model)
        if lookup == tenant_accessor + '__id__exact':
            return True
        return super().lookup_allowed(lookup, value)

class TenantStackedInline(GetQuerySetMixin, StackedInline):
    pass
