from django.contrib import admin, messages
from django.contrib.admin.utils import flatten_fieldsets
from django.db.models import ManyToManyField
from django.http.response import HttpResponse
from django.utils import timezone
from django.utils.html import format_html

from intranet.femida.src.core.admin import format_url, pretty_json, describe
from intranet.femida.src.offers.controllers import OfferCtl, LinkCtl, PreprofileCtl
from intranet.femida.src.offers.reports import generate_rejected_offers_csv, generate_offers_csv
from intranet.femida.src.offers.tasks import close_job_issues_task, finish_references_task
from intranet.femida.src.startrek.admin import get_st_changelog_url

from . import choices, models


def fieldset(name=None, fields=None, collapse=False):
    return (name, {
        'fields': fields or (),
        'classes': ('collapse',) if collapse else (),
    })


def st_url_field(queue):
    field_name = f'startrek_{queue.lower()}_key'

    @describe(f'{queue.upper()} тикет', field_name)
    def func(self, obj):
        key = getattr(obj, field_name, None)
        return get_st_changelog_url(key)

    return func


def fetch_remaining_fields(model, fieldsets, exclude=None):
    exclude = exclude or ()
    defined_fields = set(flatten_fieldsets(fieldsets))
    for field in model._meta.get_fields():
        skip_field = (
            field.name in defined_fields
            or field.auto_created
            or not field.editable
            or field.name in exclude
            or (
                isinstance(field, ManyToManyField)
                and not field.remote_field.through._meta.auto_created
            )
        )
        if not skip_field:
            yield field


class PositionAdmin(admin.ModelAdmin):

    list_display = (
        'id',
        'staff_id',
        'name_ru',
        'name_en',
        'is_deleted',
    )

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

    list_filter = (
        'is_deleted',
    )


class OfferProfileInlineAdmin(admin.StackedInline):

    model = models.OfferProfile
    exclude = (
        'creator',
    )


class OfferSchemesInlineAdmin(admin.StackedInline):

    model = models.OfferSchemesData


class OfferStatusFilter(admin.SimpleListFilter):

    title = 'status'
    parameter_name = 'status__in'

    def lookups(self, request, model_admin):
        return choices.OFFER_STATUSES

    def queryset(self, request, queryset):
        if not self.value():
            return queryset
        return queryset.filter(**{
            self.parameter_name: self.value().split(','),
        })


class OfferAdmin(admin.ModelAdmin):

    _links = (
        'st_job_url',
        'st_salary_url',
        'st_hr_url',
        'st_relocation_url',
        'st_signup_url',
        'st_adaptation_url',
        'st_eds_url',
        'ext_offer_url',
    )

    list_display = (
        'id',
        'full_name',
        'status',
    ) + _links

    list_select_related = (
        'vacancy',
    )

    raw_id_fields = [
        'abc_services',
        'application',
        'candidate',
        'creator',
        'department',
        'position',
        'vacancy',
    ]
    readonly_fields = (
        'bp_transaction_id',
        'closed_at',
        'created',
        'docs_scans',
        'eds_phone',
        'ext_offer_url',
        'is_eds_phone_verified',
        'is_resident',
        'modified',
        'newhire_id',
        'newhire_status',
        'oebs_person_id',
        'rsu',
    ) + _links

    search_fields = (
        '=id',
        '=startrek_salary_key',
        '=startrek_hr_key',
        '=startrek_relocation_key',
        '=startrek_signup_key',
        '=startrek_adaptation_key',
        '=vacancy__startrek_key',
        'full_name',
    )
    list_filter = (
        OfferStatusFilter,
    )

    inlines = (OfferProfileInlineAdmin, OfferSchemesInlineAdmin)

    actions = (
        'generate_link',
        'download_xls',
        'close_job_issues',
        'finish_references',
    )

    exclude = (
        'boss_old',
        'need_help_in_adaptation',
    )

    fieldsets = [
        fieldset('Ссылки', _links, collapse=True),
        fieldset('Технические поля', collapse=True, fields=(
            'created',
            'modified',
            'closed_at',
            'newhire_id',
            'newhire_status',
            'bp_transaction_id',
            'oebs_person_id',
        )),
        fieldset(fields=(
            'status',
            'candidate',
            'vacancy',
            'application',
            'creator',
        )),
        fieldset('Кандидат', (
            'full_name',
            'employee_type',
            'username',
            'form_type',
        )),
        fieldset('Место работы', (
            'org',
            'department',
            'position',
            'staff_position_name',
            'geography',
            'work_place',
            'office',
            'homeworker_location',
        )),
        fieldset('Условия оформления', (
            'join_at',
            'grade',
            'payment_type',
            'hourly_rate',
            'salary',
            'payment_currency',
            'employment_type',
            'work_hours_weekly',
            'is_main_work_place',
            'contract_type',
            'contract_term',
            'contract_term_date',
            'probation_period',
            'probation_period_unit',
        )),
        fieldset('Плюшки', (
            'vmi',
            'sick_leave_supplement',
            'housing_program',
            'cellular_compensation',
            'internet_compensation_amount',
            'rsu',
            'rsu_cost',
            'signup_bonus',
            'signup_2year_bonus',
            'bonus_type',
            'bonus',
            'bonus_2year',
            'allowance',
            'need_relocation',
            'relocation_package',
        )),
        fieldset('Согласование', (
            'abc_services',
            'other_payments',
            'profession',
            'professional_level',
            'programming_language',
            'salary_expectations',
            'salary_expectations_currency',
            'current_company',
            'source',
            'source_description',
        )),
        fieldset('Документы', collapse=True, fields=(
            'docs_processing_status',
            'docs_processing_resolution',
            'docs_request_count',
            'passport_data',
            'registration_address_data',
            'residence_address_data',
            'snils_number',
            'eds_phone',
            'is_eds_phone_verified',
            'docs_scans',
        )),
        fieldset('Тикеты', collapse=True, fields=(
            'startrek_salary_key',
            'startrek_hr_key',
            'startrek_relocation_key',
            'startrek_signup_key',
            'startrek_bonus_key',
            'startrek_adaptation_key',
            'startrek_hdrfs_key',
            'startrek_bootcamp_key',
            'startrek_eds_key',
        )),
    ]

    # Автоматом добавляем в форму все оставшиеся поля
    _remaining_fields = []
    for field in fetch_remaining_fields(models.Offer, fieldsets, exclude):
        _remaining_fields.append(field.name)
        if field.is_relation:
            raw_id_fields.append(field.name)
    if _remaining_fields:
        fieldsets.append(fieldset('Остальные поля', _remaining_fields, collapse=True))

    st_job_url = st_url_field('job')
    st_salary_url = st_url_field('salary')
    st_hr_url = st_url_field('hr')
    st_relocation_url = st_url_field('relocation')
    st_signup_url = st_url_field('signup')
    st_adaptation_url = st_url_field('adaptation')
    st_eds_url = st_url_field('eds')

    def get_queryset(self, request):
        return super().get_queryset(request).select_related('link')

    @describe('Сканы документов')
    def docs_scans(self, obj):
        att_urls = []
        for att in obj.attachments.all():
            att_urls.append(format_url(att.attached_file.url, att.name))
        return format_html('<br>'.join(att_urls))

    @describe('Ссылка на внешнюю анкету')
    def ext_offer_url(self, obj):
        return format_url(OfferCtl(obj).link.url)

    @describe('Создать внешнюю ссылку')
    def generate_link(self, request, queryset):
        if queryset.count() > 1:
            messages.error(request, 'Действие выполнимо только для одного оффера')
            return

        instance = queryset.first()
        if instance.is_internal:
            messages.error(request, 'Действие выполнимо только для внешнего оффера')
            return

        ctl = OfferCtl(instance, request.user)
        ctl.create_link()
        ctl.activate_link()
        messages.success(request, format_html(
            'Успешно! %s' % format_url(ctl.link.url, 'Ссылка на внешнюю анкету')
        ))

    @describe('Выгрузка Excel')
    def download_xls(self, request, queryset):
        data = generate_offers_csv(queryset)
        response = HttpResponse(data, content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = (
            'attachment; filename=offers-{time}.xls'.format(
                time=timezone.now().strftime('%Y%m%d-%H%M')
            )
        )
        return response

    @describe('Закрыть JOB-тикеты')
    def close_job_issues(self, request, queryset):
        if queryset.exclude(status=choices.OFFER_STATUSES.closed).exists():
            messages.error(request, 'Выполнимо только для закрытых офферов')
            return

        messages.success(request, 'Процесс закрытия JOB-тикетов запущен')
        offer_ids = list(queryset.values_list('id', flat=True))
        close_job_issues_task.delay(offer_ids)

    @describe('Завершить процесс рекомендаций')
    def finish_references(self, request, queryset):
        if queryset.exclude(status=choices.OFFER_STATUSES.closed).exists():
            messages.error(request, 'Выполнимо только для закрытых офферов')
            return

        messages.success(request, 'Завершение процесса рекомендаций запущено')
        offer_ids = list(queryset.values_list('id', flat=True))
        finish_references_task.delay(offer_ids)


class OfferRejectionAdmin(admin.ModelAdmin):

    list_display = (
        'id',
        'offer',
        'rejection_side',
        'rejection_reason',
        'modified',
    )

    readonly_fields = (
        'creator',
    )

    superuser_only_editable_fields = (
        'offer',
        'rejection_reason',
        'rejection_side',
        'competing_company',
        'competing_offer_conditions',
        'comment',
    )

    list_filter = (
        'rejection_side',
    )

    actions = (
        'download_xls',
    )

    def get_readonly_fields(self, request, obj=None):
        readonly_fields = super().get_readonly_fields(request, obj)
        if request.user.is_superuser:
            return readonly_fields
        return readonly_fields + self.superuser_only_editable_fields

    @describe('Выгрузка Excel')
    def download_xls(self, request, queryset):
        data = generate_rejected_offers_csv(queryset)
        response = HttpResponse(data, content_type='application/vnd.ms-excel')
        response['Content-Disposition'] = (
            'attachment; filename=rejected_offers-{time}.xls'.format(
                time=timezone.now().strftime('%Y%m%d-%H%M')
            )
        )
        return response


class OfferTemplateAdmin(admin.ModelAdmin):

    list_display = (
        'offer',
        'raw_template',
        'is_active',
    )
    raw_id_fields = (
        'offer',
    )


class PreprofileAdmin(admin.ModelAdmin):

    list_display = (
        'id',
        'ext_preprofile_url',
        'is_saved',
        'st_hr_url',
    )

    list_select_related = (
        'link',
    )

    search_fields = (
        'id',
    )

    readonly_fields = (
        'pretty_data',
    )

    actions = (
        'generate_link',
    )

    st_hr_url = st_url_field('hr')

    def get_exclude(self, request, obj=None):
        exclude = super().get_exclude(request, obj)
        if obj:
            # Не даем редактировать ID
            return tuple(exclude or ()) + ('id',)
        return exclude

    @describe('Ссылка на внешнюю анкету')
    def ext_preprofile_url(self, obj):
        return format_url(LinkCtl(obj.link).url)

    def pretty_data(self, obj):
        return pretty_json(obj.data)

    @describe('Создать внешнюю ссылку')
    def generate_link(self, request, queryset):
        if queryset.count() > 1:
            messages.error(request, 'Действие выполнимо только для одного препрофайла')
            return

        ctl = PreprofileCtl(queryset.first())
        ctl.create_link()
        messages.success(request, format_html(
            'Успешно! %s' % format_url(ctl.link.url, 'Ссылка на внешнюю анкету')
        ))


class BrochureAdmin(admin.ModelAdmin):

    list_display = (
        'name',
        'is_active',
    )
    raw_id_fields = (
        'attachment',
    )


admin.site.register(models.Position, PositionAdmin)
admin.site.register(models.Offer, OfferAdmin)
admin.site.register(models.OfferRejection, OfferRejectionAdmin)
admin.site.register(models.RawTemplate)
admin.site.register(models.OfferTemplate, OfferTemplateAdmin)
admin.site.register(models.Preprofile, PreprofileAdmin)
admin.site.register(models.Brochure, BrochureAdmin)
