from django_admin_listfilter_dropdown.filters import RelatedDropdownFilter, RelatedOnlyDropdownFilter
from django_object_actions import DjangoObjectActions, takes_instance_or_queryset
from guardian.admin import GuardedModelAdminMixin
from import_export import resources
from import_export.admin import ImportExportMixin
from ordered_model.admin import OrderedModelAdmin
from simple_history.admin import SimpleHistoryAdmin

from django.contrib import admin, messages
from django.contrib.auth import get_user_model
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _

from lms.core.admin.mixins import AddReadonlyFieldsMixin, AdminChangeLinksMixin

from .import_export_resources import CourseGroupResource, CourseResource
from .models import (
    CategoryNode, Cohort, Course, CourseBlock, CourseCategory, CourseCity, CourseFile, CourseForSupport, CourseGroup,
    CourseModule, CourseOccupancy, CourseStudent, CourseTeam, CourseTeamForSupport, CourseVisibility, CourseWorkflow,
    LinkedCourse, Provider, ServiceAccountCourse, StudentCourseProgress, StudentModuleProgress, StudyMode, Tutor,
)
from .permissions import CourseGroupObjectPermission, CourseUserObjectPermission
from .tasks import recalculate_all_course_progresses_task

User = get_user_model()


@admin.register(StudyMode)
class StudyModeAdmin(admin.ModelAdmin):
    list_display = ('id', 'slug', 'is_active', 'created', 'modified')
    list_filter = ('is_active',)
    search_fields = (
        'name', 'slug',
    )


class ProviderResource(resources.ModelResource):
    class Meta:
        model = Provider
        import_id_fields = ('oebs_id',)
        fields = ('id', 'oebs_id', 'name', 'description',)


@admin.register(Provider)
class ProviderAdmin(ImportExportMixin, admin.ModelAdmin):
    list_display = ('name', 'is_active', 'oebs_id', 'created', 'modified')
    list_filter = ('is_active',)
    search_fields = (
        'name', 'oebs_id',
    )
    raw_id_fields = ('created_by',)
    resource_class = ProviderResource


@admin.register(CourseCity)
class CourseCityAdmin(admin.ModelAdmin):
    list_display = ('name', 'slug', 'is_active', 'created', 'modified')
    list_filter = ('is_active',)
    search_fields = (
        'name', 'slug',
    )


@admin.register(CourseCategory)
class CourseCategoryAdmin(admin.ModelAdmin):
    list_display = ('name', 'is_active', 'created', 'modified')
    list_filter = ('is_active',)
    search_fields = ('name',)
    raw_id_fields = ('parent', 'created_by',)


@admin.register(CategoryNode)
class CategoryNodeAdmin(admin.ModelAdmin):
    list_display = ('name_indent', 'path',)
    list_select_related = ('category',)

    def name_indent(self, obj: CategoryNode):
        return format_html(
            '<span style="padding-left: {0}px">{1}</span>',
            10 * (obj.depth - 1),
            str(obj.category),
        )

    name_indent.short_description = _("Категория")

    def has_change_permission(self, request, obj=None):
        return False

    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


class CourseGroupInline(admin.TabularInline):
    model = CourseGroup
    fields = ('name', 'slug', 'is_active', 'can_join', 'num_participants', 'max_participants')
    readonly_fields = fields
    extra = 0
    can_delete = False

    def has_add_permission(self, request, obj=None):
        return False


class CourseOccupancyInline(admin.TabularInline):
    model = CourseOccupancy
    fields = ('current', 'maximum')
    readonly_fields = fields
    extra = 0
    can_delete = False

    def has_add_permission(self, request, obj=None):
        return False


@admin.register(CourseWorkflow)
class CourseWorkflowAdmin(admin.ModelAdmin):
    list_display = ('name', 'is_active', 'created', 'modified')
    list_filter = ('is_active',)
    search_fields = ('name',)


class BaseCourseAdmin(admin.ModelAdmin):
    list_select_related = ('study_mode', 'occupancy', 'workflow')

    raw_id_fields = ('provider', 'author')

    def display_status(self, obj: 'Course'):
        return dict(Course.STATUS_CHOICES).get(obj.status, '')

    display_status.short_description = _("Статус")


@admin.register(Course)
class CourseAdmin(
    ImportExportMixin,
    BaseCourseAdmin,
    AdminChangeLinksMixin,
    GuardedModelAdminMixin,
    DjangoObjectActions,
    SimpleHistoryAdmin,
):
    # Переопределяем change_form_template чтобы подружить GuardedModelAdminMixin и DjangoObjectActions
    change_form_template = "admin/courses/course/change_form.html"
    inlines = [
        CourseOccupancyInline,
    ]

    filter_horizontal = ('categories', 'tags', 'teams')
    search_fields = ('id', 'name', 'slug')
    list_display = (
        'name', 'slug', 'course_type', 'is_active', 'is_archive', 'enable_groups', 'display_status',
        'created', 'modified',
    )
    list_filter = (
        'is_active',
        'study_mode',
        ('city', RelatedOnlyDropdownFilter),
        ('teams', RelatedDropdownFilter),
        'enable_groups',
        'course_type',
    )
    readonly_fields = (
        'calc_begin_date', 'calc_end_date', 'calc_enroll_begin', 'calc_enroll_end', 'enable_groups',
    )
    fieldsets = (
        (None, {'fields': [
            'course_type',
            'slug', 'name', 'shortname', 'summary', 'description', 'completion_threshold', 'is_active', 'is_archive',
            'author', 'structure', 'city', 'study_mode', 'provider', 'workflow',
            'enable_groups', 'groups_link', 'students_link', 'enrolled_users_link', 'modules_link', 'blocks_link',
            'enrollments_link',
        ]}),
        (_("Заявки"), {'fields': [
            'enrollments_only', 'multi_enrollments', 'retries_allowed',
        ]}),
        (_("Категории"), {'fields': [
            'categories',
        ]}),
        (_("Теги"), {'fields': [
            'tags',
        ]}),
        (_("Обложка"), {'fields': [
            'image_url',
        ]}),
        (_("Даты"), {'fields': [
            ('begin_date', 'end_date'),
            ('enroll_begin', 'enroll_end'),
        ]}),
        (_("Фактические даты"), {'fields': [
            ('calc_begin_date', 'calc_end_date'),
            ('calc_enroll_begin', 'calc_enroll_end'),
        ]}),
        (_("Стоимость"), {'fields': [
            'price', 'payment_method', 'paid_percent', 'payment_terms',
        ]}),
        (_("Продолжительность"), {'fields': [
            'num_hours',
        ]}),
        (_("Команды курса"), {'fields': [
            'teams',
        ]}),
        (_("HRDB"), {'fields': [
            'hrdb_id',
        ]}),
    )

    changelist_links = [
        ('groups', {
            "label": _("Перейти к группам студентов"),
            "short_description": _("Группы студентов"),
            "lookup_filter": "course__id__exact",
        }),
        ('students', {
            "label": _("Перейти к студентам"),
            "short_description": _("Студенты"),
            "lookup_filter": "course__id__exact",
        }),
        ('enrolled_users', {
            "label": _("Перейти к заявкам"),
            "short_description": _("Заявки"),
            "lookup_filter": "course__id__exact",
        }),
        ('modules', {
            "label": _("Перейти к модулям"),
            "short_description": _("Модули"),
            "lookup_filter": "course__id__exact",
        }),
        ('blocks', {
            "label": _("Перейти к блокам"),
            "short_description": _("Блоки"),
            "lookup_filter": "course__id__exact",
        }),
        ('enrollments', {
            "label": _("Перейти к методам зачисления"),
            "short_description": _("Методы зачисления"),
            "lookup_filter": "course__id__exact",
        }),
    ]

    actions = [
        'make_archived',
        'make_unarchived',
        'make_active',
        'make_inactive',
        'recalculate_progress',
    ]

    change_actions = [
        'recalculate_progress',
    ]

    resource_class = CourseResource

    @takes_instance_or_queryset
    def make_archived(self, request, queryset):
        queryset.update(is_archive=True)

    make_archived.label = _("Убрать в архив")
    make_archived.short_description = _("Убрать в архив")

    @takes_instance_or_queryset
    def make_unarchived(self, request, queryset):
        queryset.update(is_archive=False)

    make_unarchived.label = _("Вернуть из архива")
    make_unarchived.short_description = _("Вернуть из архива")

    @takes_instance_or_queryset
    def make_active(self, request, queryset):
        queryset.update(is_active=True)

    make_active.label = _("Активировать")
    make_active.short_description = _("Активировать")

    @takes_instance_or_queryset
    def make_inactive(self, request, queryset):
        queryset.update(is_active=False)

    make_inactive.label = _("Деактивировать")
    make_inactive.short_description = _("Деактивировать")

    @takes_instance_or_queryset
    def recalculate_progress(self, request, queryset):
        for course in queryset:
            recalculate_all_course_progresses_task.delay(course_id=course.id)

        return self.message_user(
            request=request,
            message=_('Пересчёт прогресса студентов курса(ов) запущен'),
            level=messages.INFO,
        )

    recalculate_progress.label = _("Пересчитать прогресс")
    recalculate_progress.short_description = _("Пересчитать прогресс")


@admin.register(CourseForSupport)
class CourseForSupportAdmin(BaseCourseAdmin, AdminChangeLinksMixin, SimpleHistoryAdmin):
    list_display = ('name', 'slug', 'is_active', 'is_archive', 'author')

    fieldsets = (
        (None, {'fields': [
            'slug', 'name', 'is_active', 'is_archive', 'author',
            'enable_groups', 'groups_link', 'students_link', 'enrolled_users_link',
        ]}),
        (_("Заявки"), {'fields': [
            'enrollments_only', 'multi_enrollments', 'retries_allowed',
        ]}),
        (_("Категории"), {'fields': [
            'categories',
        ]}),
        (_("Команды курса"), {'fields': [
            'teams',
        ]}),
    )

    changelist_links = [
        ('groups', {
            "label": _("Группы студентов"),
            "short_description": _("Группы студентов"),
            "lookup_filter": "course__id__exact",
        }),
        ('students', {
            "label": _("Студенты"),
            "short_description": _("Студенты"),
            "lookup_filter": "course__id__exact",
        }),
        ('enrolled_users', {
            "label": _("Заявки"),
            "short_description": _("Заявки"),
            "lookup_filter": "course__id__exact",
        }),
    ]

    search_fields = ('id', 'name', 'slug')


@admin.register(CourseGroupObjectPermission)
class CourseGroupObjectPermissionAdmin(admin.ModelAdmin):
    raw_id_fields = ('group', 'permission', 'content_object')


@admin.register(CourseUserObjectPermission)
class CourseUserObjectPermissionAdmin(admin.ModelAdmin):
    raw_id_fields = ('user', 'permission', 'content_object')


class StudentInline(admin.TabularInline):
    model = CourseStudent
    fields = ('user',)
    readonly_fields = fields
    extra = 0
    can_delete = False

    def has_add_permission(self, request, obj=None):
        return False


@admin.register(CourseGroup)
class CourseGroupAdmin(ImportExportMixin, AdminChangeLinksMixin, SimpleHistoryAdmin):
    list_display = (
        'name', 'slug', 'course', 'is_active', 'can_join',
        'num_participants', 'max_participants', 'hrdb_id',
        'created', 'modified',
    )

    list_select_related = ('course',)
    list_filter = (
        'is_active',
        'can_join',
        ('course', RelatedOnlyDropdownFilter),
    )
    search_fields = (
        'name', 'slug', 'course__id', 'course__name',
    )
    raw_id_fields = ('course', 'tutor')
    readonly_fields = ('num_participants',)

    fieldsets = (
        (None, {'fields': [
            'course', 'slug', 'name', 'is_active', 'can_join', 'tutor',
            'max_participants', 'num_participants', 'members_link', 'enrolled_users_link',
        ]}),
        (_("HRDB"), {'fields': [
            'hrdb_id',
        ]}),
        (_("Переопределение настроек курса"), {'fields': [
            ('begin_date', 'end_date'),
            ('enroll_begin', 'enroll_end'),
            'price', 'payment_method', 'paid_percent', 'payment_terms',
            'num_hours',
        ], 'classes': ('collapse',), }),
    )

    changelist_links = [
        ('members', {
            "label": _("Студенты"),
            "short_description": _("Студенты"),
            "lookup_filter": "group__id__exact",
            "model": "courses.CourseStudent",
        }),
        ('enrolled_users', {
            "label": _("Заявки"),
            "short_description": _("Заявки"),
            "lookup_filter": "group__id__exact",
            "model": "enrollments.EnrolledUser",
        }),
    ]

    resource_class = CourseGroupResource


@admin.register(CourseStudent)
class CourseStudentAdmin(SimpleHistoryAdmin):
    list_display = ('user', 'course', 'group', 'is_passed', 'passing_date', 'status', 'created', 'modified')
    list_select_related = ('user', 'course', 'group')
    list_filter = (
        ('course', RelatedOnlyDropdownFilter),
        ('group', RelatedOnlyDropdownFilter),
        'status',
        'is_passed',
    )
    search_fields = (
        'user__id', 'user__username', 'user__yauid',
        'course__id', 'course__name',
        'group__id', 'group__name',
    )
    autocomplete_fields = ('course',)
    raw_id_fields = ('user', 'course', 'group')


@admin.register(CourseFile)
class CourseFileAdmin(admin.ModelAdmin):
    list_display = ('filename', 'size', 'mimetype', 'course', 'status', 'created', 'modified')
    list_select_related = ('course',)
    raw_id_fields = ('course', 'uploaded_by')
    search_fields = (
        'course__id', 'course__name', 'course__slug',
    )
    list_filter = ('status',)
    readonly_fields = ('uploaded_by',)


@admin.register(CourseVisibility)
class CourseVisibilityAdmin(DjangoObjectActions, admin.ModelAdmin):
    list_display = ('course', 'comments', 'is_active', 'created', 'modified')
    list_select_related = ('course',)
    list_filter = ('is_active',)
    search_fields = (
        'course__id', 'course__name', 'course__slug',
    )
    raw_id_fields = ('course',)

    fields = ('course', 'rules', 'formula', 'parameters', 'comments', 'is_active')
    readonly_fields = ('formula', 'parameters',)


@admin.register(CourseTeam)
class CourseTeamAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
    list_display = ('name', 'permission_preset')
    list_select_related = ('permission_preset',)
    list_filter = (
        ('courses', RelatedDropdownFilter),
        ('permission_preset', RelatedOnlyDropdownFilter),
    )
    search_fields = (
        'name',
        'user__username',
    )
    fields = ('name', 'permission_preset', 'permissions')
    filter_horizontal = ('permissions',)

    changelist_links = [
        ('courses', {
            'label': _("Курсы"),
            'short_description': _("Доступ к курсам"),
            'model': 'courses.Course',
            'lookup_filter': 'teams__group_ptr__exact',
        }),
        ('user', {
            'label': _("Пользователи"),
            'short_description': _("Участники команды"),
            'model': 'users.User',
            'lookup_filter': 'groups__id__exact',
        })
    ]

    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        if db_field.name == 'permissions':
            qs = kwargs.get('queryset', db_field.remote_field.model.objects)
            # Avoid a major performance hit resolving permission names which
            # triggers a content_type load:
            kwargs['queryset'] = qs.select_related('content_type')
        return super().formfield_for_manytomany(db_field, request=request, **kwargs)


@admin.register(CourseTeamForSupport)
class CourseTeamForSupportAdmin(CourseTeamAdmin):
    fields = ('name', 'permission_preset')
    changelist_links = [
        ('courses', {
            'label': _("Курсы"),
            'short_description': _("Доступ к курсам"),
            'model': 'courses.CourseForSupport',
            'lookup_filter': 'teams__group_ptr__exact',
        }),
        ('user', {
            'label': _("Пользователи"),
            'short_description': _("Участники команды"),
            'model': 'users.UserForSupport',
            'lookup_filter': 'groups__id__exact',
        })
    ]


@admin.register(CourseModule)
class CourseModuleAdmin(OrderedModelAdmin):
    list_display = (
        'name', 'module_type', 'course', 'block', 'is_active', 'weight', 'weight_scaled',
        'created', 'modified', 'move_up_down_links'
    )
    list_select_related = ('module_type', 'course', 'block')
    list_filter = (
        ('course', RelatedOnlyDropdownFilter),
        ('block', RelatedOnlyDropdownFilter),
        'module_type',
        'is_active',
    )
    raw_id_fields = ('course', 'block',)

    fields = (
        'course', 'block', 'module_type', 'name', 'description', 'is_active', 'weight', 'weight_scaled',
        'order', 'estimated_time',
    )
    readonly_fields = ('module_type', 'order')

    def has_add_permission(self, request) -> bool:
        return False


@admin.register(CourseBlock)
class CourseBlockAdmin(AdminChangeLinksMixin, OrderedModelAdmin):
    list_display = ('name', 'course', 'is_active', 'created', 'modified', 'move_up_down_links')
    list_select_related = ('course',)
    list_filter = (
        ('course', RelatedOnlyDropdownFilter),
        'is_active',
    )
    raw_id_fields = ('course',)

    fields = (
        'course', 'name', 'summary', 'is_active', 'order', 'modules_link',
    )

    readonly_fields = ('order',)

    changelist_links = [
        ('modules', {
            "label": _("Перейти к модулям"),
            "short_description": _("Модули"),
            "lookup_filter": "block__id__exact",
        }),
    ]


@admin.register(Tutor)
class TutorAdmin(admin.ModelAdmin):
    list_display = ('__str__', 'is_internal', 'position', 'is_active',)
    raw_id_fields = ('user',)
    list_select_related = ('user',)


@admin.register(Cohort)
class CohortAdmin(admin.ModelAdmin):
    search_fields = ('name', 'course__name')
    list_display = ('course', 'name', 'is_active')
    raw_id_fields = ('course', 'users')
    list_select_related = ('course',)

    list_filter = (
        ('course', RelatedOnlyDropdownFilter),
        'status',
    )


@admin.register(StudentCourseProgress)
class StudentCourseProgressAdmin(AddReadonlyFieldsMixin, SimpleHistoryAdmin):
    search_fields = ('student__user__username', 'course__slug', 'course__name')
    list_display = ('display_user', 'course', 'score', 'created', 'modified',)
    list_select_related = ('student', 'student__user', 'course',)
    raw_id_fields = ('student', 'course',)
    list_filter = (
        ('course', RelatedOnlyDropdownFilter),
    )

    readonly_fields = ('display_user', 'course', 'student',)

    def display_user(self, instance: StudentCourseProgress):
        return instance.student.user

    display_user.short_description = _("пользователь")


@admin.register(StudentModuleProgress)
class StudentModuleProgressAdmin(AddReadonlyFieldsMixin, admin.ModelAdmin):
    search_fields = ('student__user__username', 'module__name', 'course__slug', 'course__name')
    list_display = ('display_user', 'module', 'course', 'score', 'score_scaled', 'created', 'modified',)
    list_select_related = ('student', 'student__user', 'module', 'course',)
    raw_id_fields = ('student', 'module', 'course',)
    list_filter = (
        ('module', RelatedOnlyDropdownFilter),
        ('course', RelatedOnlyDropdownFilter),
    )

    readonly_fields = ('display_user', 'module', 'course', 'student',)

    def display_user(self, instance: StudentModuleProgress):
        return instance.student.user

    display_user.short_description = _("пользователь")


@admin.register(LinkedCourse)
class LinkedCourseAdmin(admin.ModelAdmin):
    search_fields = ('id', 'name', 'course__slug', 'course__name', 'linked_course__slug', 'linked_course__name')
    list_display = ('name', 'course', 'linked_course', 'is_active')
    list_select_related = ('course', 'linked_course',)
    list_filter = (
        ('course', RelatedOnlyDropdownFilter),
        'is_active',
    )
    raw_id_fields = ('course', 'linked_course',)

    fields = (
        'course', 'linked_course', 'name', 'description', 'estimated_time', 'is_active',
    )


@admin.register(ServiceAccountCourse)
class ServiceAccountCourseAdmin(admin.ModelAdmin):
    list_display = [
        'course', 'service_account'
    ]
    list_select_related = ('course', 'service_account')
    search_fields = ('id', 'course__pk', 'course__slug', 'course__name',
                     'service_account__name', 'service_account__tvm_id')
    raw_id_fields = ('course',)
