# -*- coding: utf-8 -*-
import logging

from django.conf import settings
from django.db import transaction

from idm.core.models import ConductorGroup
from idm.integration import conductor

log = logging.getLogger(__name__)

GROUPS_BATCH_SIZE = 1000


def sync_groups(force: bool = False):
    remote = conductor.get_conductor_groups()

    local_active = {}
    local_inactive = {}
    for group in ConductorGroup.objects.iterator():  # type: ConductorGroup
        if group.is_active:
            local_active[group.external_id] = group
        else:
            local_inactive[group.external_id] = group

    remote_keys = set(remote.keys())
    local_active_keys = set(local_active.keys())
    local_inactive_keys = set(local_inactive.keys())

    to_add = sorted(remote_keys - local_active_keys - local_inactive_keys)
    to_remove = sorted(local_active_keys - remote_keys)
    to_update = sorted([
        key for key
        in (remote_keys & (local_active_keys | local_inactive_keys))
        if remote[key] != (local_active.get(key) or local_inactive.get(key)).name
    ])
    # Группы, которые надо ТОЛЬКО восстановить, без обновления полей
    to_restore = sorted(((remote_keys - local_active_keys) & local_inactive_keys) - set(to_update))

    # TODO: раскомментировать после IDM-7412: Сделать мониторинги на время последнего успешного завершения тасок
    # if not force and len(to_remove) > settings.IDM_CONDUCTOR_REMOVED_GROUPS_THRESHOLD:
    #     log.error(
    #         'sync_conductor_groups: removal threshold violation (%s > %s)',
    #         len(to_remove),
    #         settings.IDM_CONDUCTOR_REMOVED_GROUPS_THRESHOLD,
    #     )
    #     raise RuntimeError('sync_conductor_groups: removal threshold violation')

    for batch_index in range(0, len(to_add), GROUPS_BATCH_SIZE):
        with transaction.atomic():
            batch_keys = to_add[batch_index:batch_index+GROUPS_BATCH_SIZE]
            for key in batch_keys:
                try:
                    ConductorGroup.objects.create(external_id=key, name=remote[key])
                except Exception:
                    log.exception('Fail while creating conductor group with external_id=%s', key)

    for batch_index in range(0, len(to_restore), GROUPS_BATCH_SIZE):
        with transaction.atomic():
            batch_keys = to_restore[batch_index:batch_index+GROUPS_BATCH_SIZE]
            try:
                objects = ConductorGroup.objects.filter(external_id__in=batch_keys).order_by('external_id')
                objects.lock_by_select()
                objects.update(is_active=True)
            except Exception:
                log.exception('Fail while restoring conductor groups')

    for batch_index in range(0, len(to_remove), GROUPS_BATCH_SIZE):
        with transaction.atomic():
            batch_keys = to_remove[batch_index:batch_index + GROUPS_BATCH_SIZE]
            try:
                objects = ConductorGroup.objects.filter(external_id__in=batch_keys).order_by('external_id')
                objects.lock_by_select()
                objects.update(is_active=False)
            except Exception:
                log.exception('Fail while removing conductor groups')

    for batch_index in range(0, len(to_update), GROUPS_BATCH_SIZE):
        with transaction.atomic():
            batch_keys = to_update[batch_index:batch_index+GROUPS_BATCH_SIZE]
            for key in batch_keys:
                try:
                    group_obj = local_active.get(key) or local_inactive.get(key)
                    group_obj.name = remote[key]
                    group_obj.is_active = True
                    group_obj.save(update_fields=['is_active', 'name'])
                except Exception:
                    log.exception('Fail while updating conductor group with external_id=%s', key)


