from itertools import groupby

from django.conf import settings
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.decorators.http import require_http_methods
from django.http import Http404
from django.db.models.query import EmptyQuerySet

from staff.lib.decorators import responding_json

from .models import Vacancy
from .forms import VacanciesFilterForm
from .utils import (
    filter_by_departments_heirarchy,
    filter_by_chief_departments_heirarchy,
    get_direct_chief,
    warp_recruiter,
    DepartmentsTree,
    localize_vacancy_attr,
    localize_vacancy,
    get_candidates,
)


@ensure_csrf_cookie
@require_http_methods(['GET'])
@responding_json
def vacancies_view(request):
    if settings.REDIRECT_INNER_VACANCIES_TO_FEMIDA:
        return _redirect(
            to_url='https://{}{}'.format(settings.FEMIDA_HOST, settings.INNER_VACANCIES_LIST_FEMIDA),
            status=302,
            # хак для починки фронта
            extra={'content': {'requested_chief': {'login': request.GET.get('chief', '')}}}
        )

    form = VacanciesFilterForm(request.GET)
    if not form.is_valid():
        return {'errors': form.errors}, 400

    vacancies_qs = (
        Vacancy.objects
        .filter(date_close=None)
    )

    # Фильтруем необходимые подразделение
    if form.cleaned_data['department']:
        vacancies_qs = filter_by_departments_heirarchy(
            vacancies_qs, [form.cleaned_data['department']]
        )

    # Фильтруем по подразделениям руководителя
    if form.cleaned_data['chief']:
        vacancies_qs = filter_by_chief_departments_heirarchy(
            vacancies_qs, form.cleaned_data['chief']
        )

    possible_programs = []
    possible_grade_programs = []
    possible_professional_levels = []

    # qs.none() ломается, елси его потом мучать и все фильтры следатют
    if not isinstance(vacancies_qs, EmptyQuerySet):
        possible_programs = (
            vacancies_qs
            .values_list('recommendation_program', flat=True)
            .distinct()
        )

        # Фильтруем по программе рекоммендаций
        recommendation_program = form.cleaned_data['recommendation_program']
        if recommendation_program:
            vacancies_qs = vacancies_qs.filter(
                recommendation_program__in=recommendation_program
            )

        possible_grade_programs = (
            vacancies_qs
            .values_list('grade_program', flat=True)
            .distinct()
        )

        # Фильтруем по программе грейдов
        grade_program = form.cleaned_data['grade_program']
        if grade_program:
            vacancies_qs = vacancies_qs.filter(
                grade_program__in=grade_program
            )

        possible_professional_levels = (
            vacancies_qs
            .values_list('professional_level', flat=True)
            .distinct()
        )

        # Фильтруем по профессиональному уровню
        professional_level = form.cleaned_data['professional_level']
        if professional_level:
            vacancies_qs = vacancies_qs.filter(
                professional_level__in=professional_level
            )

        vacancies_qs = (
            vacancies_qs
            .values(
                'id',
                'department',
                'name',
                'name_en',
                'recommendation_program',
                'grade_program',
                'professional_level',
                'profession_id',
                'profession__name',
                'profession__name_en'
            )
            .order_by('department__lft', 'id')
        )

    # Получаем родителей подразделений с вакансиями
    departments_tree = DepartmentsTree(
        list(vacancies_qs.values_list('department', flat=True))
    )

    result = []
    for dep, vacancies in groupby(vacancies_qs, lambda v: v['department']):
        result.append({
            'department_chain': departments_tree[dep][:-1],
            'department': departments_tree[dep][-1],
            'vacancies': [
                {
                    'id': vacancy['id'],
                    'name': localize_vacancy_attr(vacancy, 'name'),
                    'recommendation_program': vacancy['recommendation_program'],
                    'grade_program': vacancy['grade_program'],
                    'professional_level': vacancy['professional_level'],
                    'profession': {
                        'id': vacancy['profession_id'],
                        'name': localize_vacancy_attr(vacancy, 'profession__name')
                    },
                } for vacancy in vacancies
            ],
        })

    result = {'content': {'vacancies': result}}

    if form.cleaned_data['department']:
        result['content']['requested_department'] = {
            'name': form.cleaned_data['department'].i_name,
            'url': form.cleaned_data['department'].url,
            'id': form.cleaned_data['department'].id,
        }

    if form.cleaned_data['chief']:
        result['content']['requested_chief'] = {
            'first_name': form.cleaned_data['chief'].i_first_name,
            'last_name': form.cleaned_data['chief'].i_last_name,
            'login': form.cleaned_data['chief'].login,
            'id': form.cleaned_data['chief'].id,
        }

    if form.cleaned_data['recommendation_program']:
        result['content']['requested_programs'] = {
            p: 1 for p in form.cleaned_data['recommendation_program']
        }

    result['content']['possible_programs'] = {
        p: 1 for p in possible_programs
    }

    if form.cleaned_data['grade_program']:
        result['content']['requested_grade_programs'] = {
            p: 1 for p in form.cleaned_data['grade_program']
        }

    result['content']['possible_grade_programs'] = {
        p: 1 for p in possible_grade_programs
    }

    if form.cleaned_data['professional_level']:
        result['content']['requested_professional_levels'] = {
            p: 1 for p in form.cleaned_data['professional_level']
        }

    result['content']['possible_professional_levels'] = {
        p: 1 for p in possible_professional_levels
    }

    return result


@require_http_methods(['GET'])
@responding_json
def vacancy_view(request, vacancy_id):
    try:
        vacancy = dict(
            Vacancy.objects
            .values(
                'id',
                'name',
                'name_en',
                'department',
                'description',
                'description_en',
                'date_open',
                'date_close',
                'femida_link',
                'reason',
                'recruiter__native_lang',
                'recruiter__first_name',
                'recruiter__last_name',
                'recruiter__first_name_en',
                'recruiter__last_name_en',
                'recruiter__login',
                'recruiter',
                'vacancy_url',
                'recommendation_program',
                'grade_program',
                'professional_level',
                'profession_id',
                'profession__name',
                'profession__name_en'
            )
            .get(id=vacancy_id)
        )
    except Vacancy.DoesNotExist:
        raise Http404('Vacancy not found.')
    if settings.REDIRECT_INNER_VACANCIES_TO_FEMIDA:
        femida_link = vacancy['femida_link']
        if not femida_link:
            return Http404('Have no attached femida vacancy')
        try:
            id_ = int(femida_link)
            host_tmpl = 'https://{}{}'.format(settings.FEMIDA_HOST, settings.INNER_VACANCIES_FEMIDA_TEMPLATE)
            femida_link = host_tmpl.format(id=id_)
        except ValueError:
            pass
        return _redirect(femida_link, 302)

    localize_vacancy(vacancy)
    warp_recruiter(vacancy)

    # Получим цепочку подразделений
    departments_tree = DepartmentsTree([vacancy['department']])
    department_chain = departments_tree[vacancy['department']]
    vacancy['department_chain'] = department_chain[:-1]
    vacancy['department'] = department_chain[-1]

    vacancy['profession'] = {
        'id': vacancy.pop('profession_id'),
        'name': vacancy.pop('profession__name')
    }

    # Определим непосредственного руководителя подразделения
    # в котором открыта вакансия
    chief = get_direct_chief([d['id'] for d in department_chain])
    vacancy['chief'] = chief

    return {'content': vacancy}


def _redirect(to_url, status, extra=None):
    res = {'redirect': {'url': to_url, 'status': status}}
    if extra:
        res.update(extra)
    return res


@require_http_methods(['GET'])
@responding_json
def candidates_view(request):
    return get_candidates()
