from collections import defaultdict

from django.db.models import Count, Q, F

from intranet.femida.src.core.models import City
from intranet.femida.src.api.core.permissions import StrictServicePermission
from intranet.femida.src.api.core.views import BaseView
from intranet.femida.src.api.services import serializers
from intranet.femida.src.core.db.helpers import get_count_subquery
from intranet.femida.src.publications.helpers import get_publications_lang
from intranet.femida.src.publications.models import Publication
from intranet.femida.src.publications.choices import PUBLICATION_TYPES, PUBLICATION_STATUSES
from intranet.femida.src.services.models import PublicService


class ServiceBaseView(BaseView):

    model_class = PublicService
    authentication_classes = []
    permission_classes = [
        StrictServicePermission('permissions.can_view_external_publications'),
    ]

    def get_queryset(self):
        lang = get_publications_lang()
        return (
            self.model_class.objects
            .annotate(publications_count=get_count_subquery(
                queryset=Publication.objects.published_external().filter(lang=lang),
                reverse_related_name='public_service',
            ))
        )


class ServiceListView(ServiceBaseView):

    list_item_serializer_class = serializers.PublicServiceSerializer

    def get_queryset(self):
        lang = get_publications_lang()
        return (
            super().get_queryset()
            .filter(is_active=True)
            .order_by(f'name_{lang}')
        )

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def get_list_item_serializer_context(self):
        lang = get_publications_lang()

        cities_qs = (
            City.objects
            .filter(is_active=True)
            .annotate(
                public_service_id=F('vacancies__publications__public_service'),
                publications_count=Count(
                    'vacancies__publications',
                    filter=Q(
                        vacancies__publications__type=PUBLICATION_TYPES.external,
                        vacancies__publications__status=PUBLICATION_STATUSES.published,
                        vacancies__publications__lang=lang,
                    ),
                ),
            )
            .values_list(
                'id',
                'public_service_id',
                'publications_count',
            )
        )
        city_ids_by_service = defaultdict(list)
        publications_count_by_city_service = {}
        for city_id, pub_service_id, publication_count in cities_qs:
            publications_count_by_city_service[(city_id, pub_service_id)] = publication_count
            city_ids_by_service[pub_service_id].append(city_id)

        return {
            'publications_count_by_city_service': publications_count_by_city_service,
            'city_by_id': City.objects.in_bulk(),
            'city_ids_by_service': city_ids_by_service,
        }


class ServiceDetailView(ServiceBaseView):

    detail_serializer_class = serializers.PublicServiceSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
