from typing import Optional, List

from django.db.models import Q

from staff.departments.models import HeadcountPosition, Department
from staff.headcounts.permissions import Permissions
from staff.lib.utils.qs_values import localize, repack_related
from staff.oebs.constants import PERSON_POSITION_STATUS
from staff.person.models import Staff

from staff.proposal.controllers.department import order_field
from staff.proposal.controllers.utils import raw_data


class HeadcountDataCtl(object):
    headcount_fields = (
        'id',
        'name',
        'code',
        'status',

        'department_id',
        'department__url',
        'department__level',
        'department__tree_id',
        'department__lft',
        'department__name',
        'department__name_en',
    )

    def __init__(self, headcounts_codes: List[int], observer: Optional[Staff]):
        self._observer = observer
        self._meta_data = {}

        free_hc_filter = Q(status__in=(PERSON_POSITION_STATUS.VACANCY_PLAN, PERSON_POSITION_STATUS.RESERVE))
        _filter = Q(code__in=headcounts_codes) & free_hc_filter

        if observer:
            department_ids_qs = (
                Permissions(observer)
                .filter_by_observer(Department.objects.all())
                .values_list('id', flat=True)
            )

            valuestream_ids_qs = (
                Permissions(observer)
                .filter_by_observer(Department.valuestreams.all())
                .values_list('id', flat=True)
            )

            _filter &= (
                Q(department_id__in=department_ids_qs) | Q(valuestream_id__in=valuestream_ids_qs)
            )

        headcount_data_qs = (
            HeadcountPosition.objects
            .filter(_filter)
            .values(*self.headcount_fields)
            .order_by('code')
        )
        self.headcounts_data = {v['code']: repack_related(v) for v in headcount_data_qs}

    def as_form_data(self, headcount_code):
        from staff.proposal.forms.headcount import HeadcountEditForm

        if not self.headcounts_data or headcount_code not in self.headcounts_data:
            return {}

        result = raw_data(HeadcountEditForm().data_as_dict())
        result['headcount_code'] = headcount_code
        return result

    def as_meta(self, headcount_code):
        if not self.headcounts_data or headcount_code not in self.headcounts_data:
            return {}

        meta = localize(self.headcounts_data[headcount_code].copy())

        meta['department_url'] = meta['department']['url']
        meta['department_level'] = meta['department']['level']
        tree_id = meta['department']['tree_id']
        lft = meta['department']['lft']
        meta['department_order_field'] = order_field(tree_id, lft) if tree_id and lft else 0
        localize(meta['department'])
        meta['department_name'] = meta['department']['name']
        meta.pop('department')
        meta['headcount_code'] = meta['code']  # code must be!

        return meta
