from adminsortable2.admin import SortableInlineAdminMixin, SortableAdminMixin
from django.contrib import admin
from django.core.exceptions import ValidationError
from django.forms.models import BaseInlineFormSet, ModelForm
from django_summernote.admin import SummernoteModelAdmin
from embed_video.admin import AdminVideoMixin
from tasks.constants import ApprenticeTaskAnswerStatus
from tasks.models import Task, ExerciseTaskPosition, Path, TaskMarkCriteria, ApprenticeTaskAnswer, ApprenticeVideo, \
    MentorTaskMarkCriteriaApprenticeVideoValue, ApprenticeTaskMarkCriteriaApprenticeVideo, MentorApprenticeVideoOpinion


class TaskInline(SortableInlineAdminMixin, admin.TabularInline):  # or admin.StackedInline
    model = Task


class PathAdmin(SortableAdminMixin, admin.ModelAdmin):
    list_display = ('name', 'id')
    inlines = (TaskInline,)


class ExerciseInline(SortableInlineAdminMixin, admin.TabularInline):  # or admin.StackedInline
    model = ExerciseTaskPosition


class TaskMarkCriteriaInline(admin.StackedInline):  # or admin.TabularInline
    model = TaskMarkCriteria


class TaskAdmin(AdminVideoMixin, SummernoteModelAdmin):
    list_display = ('title', 'id', 'path', 'is_active', 'yt_video')
    filter_horizontal = ('articles',)
    exclude = ('position',)
    summer_note_fields = ('description', 'instruction')
    inlines = (ExerciseInline, TaskMarkCriteriaInline)


class ApprenticeTaskAnswerAdmin(admin.ModelAdmin):
    list_display = (
        'id', 'created', 'task_title', 'path_name', 'apprentice', 'status', 'custom_title', 'mentor_text_score',
        'mentor_score', 'notification')

    def task_title(self, instance):
        return instance.task.title

    task_title.short_description = "Zadanie"
    task_title.admin_order_field = 'task__title'

    def path_name(self, instance):
        return instance.task.path.name

    path_name.short_description = "Ścieżka"
    path_name.admin_order_field = 'task__path__name'

    def status(self, instance):
        return ApprenticeTaskAnswerStatus.name(instance.get_status())

    status.short_description = "Status"

    def mentor_text_score(self, instance):
        return instance.video_1 is not None and instance.video_1.mentor_text_score is not None

    mentor_text_score.short_description = "Ocena tekstowa mentora"
    mentor_text_score.boolean = True

    def mentor_score(self, instance):
        if instance.video_1:
            return instance.video_1.mentor_scores.count()
        else:
            return 0

    mentor_score.short_description = "Liczba ocen punktowych mentora"


class NoTaskToSetCriteria(Exception):
    '''
    Wyjątek rzucany w przypadku kiedy nie można ustalić tasku dla którego wykonywana jest ocena
    '''
    pass


class MentorScoreInlineForm(ModelForm):
    def __init__(self, parent_object, *args, **kwargs):
        try:
            apprentice_video = parent_object
            if not apprentice_video:
                raise NoTaskToSetCriteria
            try:
                task = apprentice_video.task_answer_as_1.task
                task_mark_criteria = TaskMarkCriteria.objects.filter(task=task)
            except ApprenticeTaskAnswer.DoesNotExist:
                raise NoTaskToSetCriteria
        except NoTaskToSetCriteria:
            task_mark_criteria = TaskMarkCriteria.objects.none()

        self.base_fields['task_mark_criteria'].queryset = task_mark_criteria
        super(MentorScoreInlineForm, self).__init__(*args, **kwargs)


class MentorScoreInlineFormSet(BaseInlineFormSet):
    def get_form_kwargs(self, index):
        kwargs = super().get_form_kwargs(index)
        kwargs['parent_object'] = self.instance
        return kwargs

    def clean(self):
        cleaned_data = [score for score in self.cleaned_data if score.get('DELETE') is False]
        if len(cleaned_data) == 0:
            return self.cleaned_data
        all_mark_criteria = self.form.base_fields['task_mark_criteria'].queryset
        selected_mark_criteria = [score['task_mark_criteria'] for score in cleaned_data]
        difference = set(all_mark_criteria).difference(set(selected_mark_criteria))
        if len(difference) > 0:
            raise ValidationError('Niepełna lista ocen')
        return self.cleaned_data


class MentorScoreInline(admin.StackedInline):
    form = MentorScoreInlineForm
    formset = MentorScoreInlineFormSet
    model = MentorTaskMarkCriteriaApprenticeVideoValue
    extra = 0


class MentorOpinionInline(admin.StackedInline):
    model = MentorApprenticeVideoOpinion
    extra = 0


class ApprenticeScoreInlineForm(ModelForm):
    def __init__(self, parent_object, *args, **kwargs):
        try:
            apprentice_video = parent_object
            if not apprentice_video:
                raise NoTaskToSetCriteria
            try:
                task = apprentice_video.task_answer_as_2.task
                task_mark_criteria = TaskMarkCriteria.objects.filter(task=task)
            except ApprenticeTaskAnswer.DoesNotExist:
                raise NoTaskToSetCriteria
        except NoTaskToSetCriteria:
            task_mark_criteria = TaskMarkCriteria.objects.none()

        self.base_fields['task_mark_criteria'].queryset = task_mark_criteria
        super(ApprenticeScoreInlineForm, self).__init__(*args, **kwargs)


class ApprenticeScoreInlineFormSet(BaseInlineFormSet):
    def get_form_kwargs(self, index):
        kwargs = super().get_form_kwargs(index)
        kwargs['parent_object'] = self.instance
        return kwargs


class ApprenticeScoreInline(admin.StackedInline):
    form = ApprenticeScoreInlineForm
    formset = ApprenticeScoreInlineFormSet
    model = ApprenticeTaskMarkCriteriaApprenticeVideo
    extra = 0


class ApprenticeVideoAdmin(AdminVideoMixin, admin.ModelAdmin):
    list_display = ('yt_video', 'task_answer_as_1', 'task_answer_as_2')
    readonly_fields = ('task_answer_as_1', 'task_answer_as_2')

    def change_view(self, request, object_id, form_url='', extra_context=None):
        apprentice_video = ApprenticeVideo.objects.get(id=object_id)
        self.inlines = []
        try:
            _task_answer = apprentice_video.task_answer_as_1
            self.inlines.append(MentorScoreInline)
            self.inlines.append(MentorOpinionInline)
        except ApprenticeTaskAnswer.DoesNotExist:
            pass
        try:
            _task_answer = apprentice_video.task_answer_as_2
            self.inlines.append(ApprenticeScoreInline)
        except ApprenticeTaskAnswer.DoesNotExist:
            pass

        return super(ApprenticeVideoAdmin, self).change_view(request, object_id)


admin.site.register(Task, TaskAdmin)
admin.site.register(Path, PathAdmin)
admin.site.register(ApprenticeTaskAnswer, ApprenticeTaskAnswerAdmin)
admin.site.register(ApprenticeVideo, ApprenticeVideoAdmin)
