from django.contrib import admin, messages
from django.forms import ModelForm, ChoiceField
from django.utils import timezone

from intranet.femida.src.candidates.choices import VERIFICATION_STATUSES
from intranet.femida.src.candidates.consideration_issues.base import IssueTypesRegistry
from intranet.femida.src.candidates.tasks import (
    run_duplicates_search,
    sync_contest_participant_ids_task,
    sync_contests_results,
    update_consideration_issues_task,
    sync_contests_meta_info_task
)
from intranet.femida.src.core.admin import describe
from intranet.femida.src.core.controllers import update_instance
from intranet.femida.src.core.db.fields import format_relative_delta
from intranet.femida.src.notifications.candidates import send_verification_data_to_vendor
from intranet.femida.src.startrek.admin import get_st_changelog_url

from . import models


class CandidateCityInlineAdmin(admin.TabularInline):

    model = models.CandidateCity


class CandidateTagInlineAdmin(admin.TabularInline):

    model = models.CandidateTag
    raw_id_fields = ('tag',)


class CandidateResponsibleInlineAdmin(admin.TabularInline):

    model = models.CandidateResponsible
    raw_id_fields = ('user',)


class ConsiderationResponsibleInlineAdmin(admin.TabularInline):

    model = models.ConsiderationResponsible
    raw_id_fields = ('user',)


class ConsiderationHistoryInlineAdmin(admin.TabularInline):

    model = models.ConsiderationHistory


class CandidateAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'created_by',
        'original',
    )
    readonly_fields = (
        'beamery_id',
        'touched_at',
    )

    search_fields = (
        'id',
        'first_name',
        'middle_name',
        'last_name',
        'login',
    )

    list_display = (
        'id',
        'first_name',
        'last_name',
        'login',
        'city',
        'country',
        'status',
    )

    list_filter = (
        'status',
    )

    inlines = (
        CandidateResponsibleInlineAdmin,
        CandidateCityInlineAdmin,
        CandidateTagInlineAdmin,
    )

    def get_queryset(self, request):
        qs = self.model.objects.get_queryset()
        ordering = self.get_ordering(request)
        if ordering:
            qs = qs.order_by(*ordering)
        return qs


class ConsiderationIssueAdminForm(ModelForm):

    type = ChoiceField(choices=[(name, name) for name in IssueTypesRegistry.get_issue_types()])


class ConsiderationIssueAdmin(admin.ModelAdmin):

    form = ConsiderationIssueAdminForm

    raw_id_fields = (
        'consideration',
        'resolved_by',
    )
    list_display = (
        'id',
        'type',
        'is_resolved',
        'resolved_at',
        'resolved_by',
        'level',
    )
    list_filter = (
        'type',
        'is_resolved',
        'level',
    )
    search_fields = (
        'id',
        'consideration__id',
        'consideration__candidate__id',
        'resolved_by__username',
    )

    actions = ('update_consideration_issues',)

    @describe('Обновить список ворнингов')
    def update_consideration_issues(self, request, queryset):
        update_consideration_issues_task.delay()
        messages.success(request, 'Процесс обновления списка ворнигов запущен')


class ConsiderationAdmin(admin.ModelAdmin):

    search_fields = (
        'id',
        'created_by__username',
        'candidate__id',
        'candidate__full_name',
    )

    raw_id_fields = (
        'candidate',
        'created_by',
        'rotation',
    )

    list_display = (
        'id',
        'state',
        'candidate',
        'created_by',
    )

    list_filter = (
        'state',
    )

    list_select_related = (
        'candidate',
        'created_by',
    )

    inlines = (
        ConsiderationResponsibleInlineAdmin,
        ConsiderationHistoryInlineAdmin,
    )


class ConsiderationHistoryAdmin(admin.ModelAdmin):

    search_fields = (
        'consideration__id',
        'consideration__candidate__id',
    )

    list_display = (
        'id',
        'consideration',
        'status',
        'changed_at',
    )

    list_select_related = (
        'consideration',
    )

    raw_id_fields = (
        'consideration',
    )


class CandidateContactAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
    )

    search_fields = (
        'id',
        'candidate__id',
        'account_id',
    )

    list_display = (
        'id',
        'candidate',
        'type',
        'account_id',
        'is_main',
        'is_active',
    )

    list_filter = (
        'type',
        'is_main',
        'is_active',
    )


class CandidateEducationAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
    )

    search_fields = (
        'id',
        'candidate__id',
        'institution',
        'faculty',
    )

    list_display = (
        'id',
        'candidate',
        'institution',
        'faculty',
        'degree',
        'end_date',
    )

    list_filter = (
        'degree',
    )


class CandidateJobAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
    )

    search_fields = (
        'id',
        'candidate__id',
        'employer',
        'position',
    )

    list_display = (
        'id',
        'candidate',
        'employer',
        'position',
        'start_date',
        'end_date',
    )


class CandidateAttachmentAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
        'application',
        'attachment',
    )

    search_fields = (
        'id',
        'candidate__id',
        'attachment__id',
        'attachment__name',
    )

    list_display = (
        'id',
        'candidate',
        'attachment',
        'type',
    )

    list_filter = (
        'type',
    )


class CandidateSkillAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
        'skill',
    )

    search_fields = (
        'id',
        'candidate__id',
        'skill__id',
        'skill__name',
    )

    list_display = (
        'id',
        'candidate',
        'skill',
    )


class CandidateCityAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
    )

    search_fields = (
        'id',
        'candidate__id',
        'city__id',
        'city__name_ru',
        'city__name_en',
    )

    list_display = (
        'id',
        'candidate',
        'city',
    )


class CandidateTagAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
        'tag',
    )

    search_fields = (
        'id',
        'candidate__id',
        'tag__name',
    )

    list_display = (
        'id',
        'candidate',
        'tag',
        'is_active',
    )


class CandidateSubmissionAdmin(admin.ModelAdmin):

    search_fields = (
        '=id',
        '=candidate__id',
        '=form__id',
        'responsible__username',
        '=reference__id',
        '=forms_answer_id',
    )

    raw_id_fields = (
        'candidate',
        'responsible',
        'attachment',
        'form',
        'vacancies',
        'reference',
        'rotation',
        'publication',
    )

    list_display = (
        'id',
        'first_name',
        'last_name',
        'candidate',
        'form',
        'reference',
        'status',
        'responsible',
        'closed_at',
    )

    list_filter = (
        'status',
    )

    filter_horizontal = (
        'target_cities',
        'skills',
        'professions',
    )


class ReferenceAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'vacancies',
        'created_by',
        'processed_by',
    )

    search_fields = (
        '=id',
        '=submission__id',
        'created_by__username',
        'processed_by__username',
    )

    readonly_fields = (
        'created',
        'modified',
    )

    list_display = (
        'id',
        'created_by',
        'status',
        'expiration_date',
        'submission',
        'startrek_url',
    )

    list_filter = (
        'status',
    )

    list_select_related = (
        'submission',
        'created_by',
    )

    def startrek_url(self, obj):
        return get_st_changelog_url(obj.startrek_key)


class RotationAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'vacancies',
        'created_by',
    )

    search_fields = (
        '=id',
        '=submission__id',
        'created_by__username',
        '=startrek_rotation_key',
        '=startrek_myrotation_key',
    )

    readonly_fields = (
        'created',
        'modified',
    )

    list_display = (
        'id',
        'created_by',
        'status',
        'submission',
        'startrek_rotation_url',
        'startrek_myrotation_url',
    )

    list_filter = (
        'status',
    )

    list_select_related = (
        'submission',
        'created_by',
    )

    def startrek_rotation_url(self, obj):
        return get_st_changelog_url(obj.startrek_rotation_key)

    def startrek_myrotation_url(self, obj):
        return get_st_changelog_url(obj.startrek_myrotation_key)


class CandidateProfessionAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
    )

    search_fields = (
        'id',
        'candidate__id',
    )

    list_display = (
        'id',
        'candidate',
        'profession',
        'salary_expectation',
    )

    list_filter = (
        'profession',
    )


class ChallengeAdmin(admin.ModelAdmin):

    actions = [
        'run_sync_participant_ids',
        'run_sync_contests_results',
        'run_sync_contests_meta_info'
    ]

    raw_id_fields = (
        'candidate',
        'consideration',
        'submission',
        'application',
        'reviewed_by',
        'created_by',
        'finished_by',
    )

    search_fields = (
        'id',
        'candidate__id',
        'application__id',
    )

    list_display = (
        'id',
        'candidate',
        'application',
        'reviewed_by',
    )

    @describe('Синхронизировать participant_id с Контестом')
    def run_sync_participant_ids(self, request, queryset):
        sync_contest_participant_ids_task.delay()
        messages.success(request, 'Синхронизация с Контестом запущена')

    @describe('Выгрузить результаты Контеста')
    def run_sync_contests_results(self, request, queryset):
        sync_contests_results.delay()
        messages.success(request, 'Синхронизация с Контестом запущена')

    @describe('Синхронизировать время контестов, тексты задач и прочую метаинформацию')
    def run_sync_contests_meta_info(self, request, queryset):
        sync_contests_meta_info_task.delay()
        messages.success(request, 'Синхронизация мета информации о контестах запущена')


class DuplicationCaseAdmin(admin.ModelAdmin):

    actions = ['run_search']

    raw_id_fields = (
        'first_candidate',
        'second_candidate',
        'merged_to',
        'submission',
        'managed_by',
    )

    list_display = (
        'id',
        'is_active',
        'resolution',
        'managed_by',
        'score',
        'is_auto_merge',
        'created',
    )

    list_filter = (
        'status',
        'resolution',
        'is_auto_merge',
    )

    search_fields = (
        'id',
        'first_candidate__id',
        'second_candidate__id',
    )

    def run_search(self, request, queryset):
        run_duplicates_search.delay()
        messages.success(request, 'Поиск дубликатов запущен')

    run_search.short_description = 'Запустить поиск дубликатов'


class CryptaVectorAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'submission',
    )

    list_display = (
        'id',
        'submission',
        'created',
        'yandexuid',
    )

    list_select_related = (
        'submission',
    )

    search_fields = (
        'id',
        'submission__id',
        'yandexuid',
    )

    readonly_fields = (
        'yandexuid',
        'submission',
        'parsed_vector_b',
        'parsed_vector_m',
        'parsed_vector',
    )


class VerificationAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'created_by',
        'candidate',
        'application',
    )

    search_fields = (
        '=id',
        '=startrek_ess_key',
        '=candidate__id',
        'uuid',
    )

    list_display = (
        'id',
        'uuid',
        'candidate',
        'status',
        'resolution',
        'startrek_ess_key',
    )

    list_select_related = (
        'candidate',
    )

    actions = ('resend_to_vendor',)

    @describe('Переотправить КИ вендору')
    def resend_to_vendor(self, request, queryset):
        with_wrong_statuses = queryset.exclude(status=VERIFICATION_STATUSES.on_check)
        if with_wrong_statuses.exists():
            messages.error(request, 'Действие выполнимо только для КИ со статусом on_check')
            return

        for instance in queryset:
            now = timezone.now()
            update_instance(instance, {'sent_on_check': now})
            send_verification_data_to_vendor(instance)

        messages.success(request, 'Анкеты КИ переотправлены')


class CandidateScoringAdmin(admin.ModelAdmin):

    raw_id_fields = (
        'candidate',
        'scoring_category',
    )

    list_display = (
        'id',
        'scoring_value',
        'candidate',
        'scoring_category',
        'version',
    )

    list_filter = (
        'scoring_category',
        'version',
    )

    search_fields = (
        'candidate__id',
        'scoring_category__name_ru',
        'scoring_category__name_en',
    )


class ScoringCategoryAdmin(admin.ModelAdmin):

    list_display = (
        'id',
        'name_ru',
        'name_en',
        'is_active',
    )

    list_filter = (
        'name_ru',
        'name_en',
    )

    list_editable = (
        'is_active',
    )

    search_fields = (
        'name_ru',
        'name_en',
    )


class CandidateCompoundSourceInlineAdmin(admin.TabularInline):
    model = models.CandidateCompoundSource
    extra = 1


class CandidateSourceCategoryAdmin(admin.ModelAdmin):

    fields = (
        'id',
        'name',
    )

    readonly_fields = (
        'id',
    )

    list_display = (
        'id',
        'name',
    )

    inlines = (
        CandidateCompoundSourceInlineAdmin,
    )

    search_fields = (
        'name',
    )


class CandidateSourceAdmin(admin.ModelAdmin):

    fields = (
        'id',
        'name',
        'time_to_live'
    )

    readonly_fields = (
        'id',
    )

    search_fields = (
        'name',
    )

    list_display = (
        'id',
        'name',
        'time_to_live_value',
    )

    inlines = (
        CandidateCompoundSourceInlineAdmin,
    )

    filter_horizontal = (
        'categories',
    )

    def time_to_live_value(self, obj):
        ttl = getattr(obj, 'time_to_live', None)
        return format_relative_delta(ttl) if ttl else 'inf'


class CandidateTouchAdmin(admin.ModelAdmin):

    fields = (
        'id',
        'candidate',
        'created_by',
        'created',
        'modified',
        'expiration_date',
        'source',
        'consideration',
        'application',
        'description',
        'medium',
    )

    readonly_fields = (
        'id',
        'created',
        'modified',
    )

    list_display = (
        'id',
        'candidate',
        'source',
        'expiration_date',
        'medium'
    )

    raw_id_fields = (
        'created_by',
        'candidate',
        'source',
        'consideration',
        'application',
    )

    search_fields = (
        '=id',
        '=candidate_id',
        'candidate__last_name',
        'candidate__first_name',
        'created_by__username',
    )


admin.site.register(models.Candidate, CandidateAdmin)
admin.site.register(models.Consideration, ConsiderationAdmin)
admin.site.register(models.ConsiderationHistory, ConsiderationHistoryAdmin)
admin.site.register(models.ConsiderationIssue, ConsiderationIssueAdmin)
admin.site.register(models.CandidateContact, CandidateContactAdmin)
admin.site.register(models.CandidateEducation, CandidateEducationAdmin)
admin.site.register(models.CandidateJob, CandidateJobAdmin)
admin.site.register(models.CandidateAttachment, CandidateAttachmentAdmin)
admin.site.register(models.CandidateSkill, CandidateSkillAdmin)
admin.site.register(models.CandidateCity, CandidateCityAdmin)
admin.site.register(models.CandidateTag, CandidateTagAdmin)
admin.site.register(models.CandidateProfession, CandidateProfessionAdmin)
admin.site.register(models.Challenge, ChallengeAdmin)
admin.site.register(models.DuplicationCase, DuplicationCaseAdmin)
admin.site.register(models.CandidateSubmission, CandidateSubmissionAdmin)
admin.site.register(models.Reference, ReferenceAdmin)
admin.site.register(models.Rotation, RotationAdmin)
admin.site.register(models.CryptaVector, CryptaVectorAdmin)
admin.site.register(models.Verification, VerificationAdmin)
admin.site.register(models.CandidateScoring, CandidateScoringAdmin)
admin.site.register(models.ScoringCategory, ScoringCategoryAdmin)
admin.site.register(models.CandidateSourceCategory, CandidateSourceCategoryAdmin)
admin.site.register(models.CandidateSource, CandidateSourceAdmin)
admin.site.register(models.CandidateTouch, CandidateTouchAdmin)
admin.site.register(models.CandidateCompoundSource)
