import logging
from typing import Optional, Dict

from django.conf import settings

from staff.departments.models import Department
from staff.groups.models import Group
from staff.lib.sync_tools.data_mapper import DataMapper
from staff.lib.sync_tools.rollupper import Rollupper
from staff.umbrellas.models import Umbrella

from staff.syncs.models import StartrekUmbrella, StartrekVs

logger = logging.getLogger(__name__)


class UmbrellaMapper(DataMapper):
    mapping = (
        ('issue_key', 'goal_id', lambda key: int(key.split('-', 1)[1])),
        ('issue_key', 'issue_key'),
        ('name', 'name'),
    )


class UmbrellaRollUpper(Rollupper):
    model = StartrekUmbrella
    queryset = StartrekUmbrella.objects.filter(vs__abc_service_id__isnull=False).select_related('vs')
    data_mapper_class = UmbrellaMapper
    link_field_name = 'staff_instance'
    key_field_name = 'id'
    create_absent = True

    rollup_rel_fields = [
        ('vs', {'value_stream_id': '_get_value_stream_id'}),
        ('vs', {'intranet_status': '_get_intranet_status'}),
    ]

    _value_stream_mapping: Optional[Dict[int, int]] = None

    def __init__(self, logger=None, debug=False, create_absent=False):
        known_services = self._get_value_stream_mapping()
        self.queryset = self.queryset.filter(vs__abc_service_id__in=known_services)
        super().__init__(logger, debug, create_absent)

    def create_dis_instance(self, oebs_instance: StartrekUmbrella) -> Umbrella:
        return Umbrella()

    def generic_rollup(
        self,
        oebs_instance: StartrekUmbrella,
        dis_instance: Umbrella,
        field_name: str,
        dry_run: bool,
        **kwargs,
    ) -> bool:
        actually_updated = False
        new_value = getattr(oebs_instance, field_name)

        for destination_field, mapping_function in kwargs.items():
            result_value = getattr(self, mapping_function)(new_value, oebs_instance)
            current_value = getattr(dis_instance, destination_field)

            if result_value != current_value:
                actually_updated = True
                setattr(dis_instance, destination_field, result_value)

        return actually_updated

    def _get_value_stream_mapping(self) -> Dict[int, int]:
        if self._value_stream_mapping is None:
            value_streams = dict(Department.valuestreams.active().values_list('url', 'id'))
            groups = Group.objects.active().filter(url__in=value_streams.keys()).values('service_id', 'url')

            self._value_stream_mapping = {group['service_id']: value_streams[group['url']] for group in groups}

        return self._value_stream_mapping

    def _get_value_stream_id(self, value_stream: StartrekVs, _: StartrekUmbrella) -> Optional[int]:
        return self._get_value_stream_mapping()[value_stream.abc_service_id]

    @staticmethod
    def _get_intranet_status(value_stream: StartrekVs, _: StartrekUmbrella) -> int:
        period_start = settings.ACTIVE_UMBRELLAS_PERIOD_START
        period_end = settings.ACTIVE_UMBRELLAS_PERIOD_END
        if period_start <= value_stream.deadline <= period_end:
            return 1
        return 0
