# coding: utf-8


import logging

from django.db import models
from idm.sync.staff import transfers

from idm.core import exceptions
from idm.core.constants.action import ACTION
from idm.utils.log import log_duration
from idm.utils.actions import start_stop_actions


log = logging.getLogger(__name__)


class TransferQuerySet(models.QuerySet):
    def unprocessed(self):
        return self.filter(state='created')

    def undecided(self):
        return self.filter(state='undecided')

    def decided(self):
        return self.exclude(state='undecided')

    def new(self):
        return self.filter(is_new=True)

    def old(self):
        return self.filter(is_new=False)

    def auto_reject(self):
        for transfer in self:
            try:
                transfer.reject(bypass_checks=True, state='auto_rejected')
            except exceptions.TransferStateSwitchError:
                # Перемещение нельзя подтвердить – скорее всего оно уже перешло в expired. Игнорируем этот случай
                pass

    def accept(self, requester):
        for transfer in self:
            try:
                transfer.accept(requester=requester)
            except exceptions.TransferStateSwitchError:
                # Перемещение нельзя подтвердить – скорее всего оно уже перешло в expired. Игнорируем этот случай
                pass

    def auto_accept(self):
        errors = successes = 0
        for transfer in self:
            try:
                transfer.accept(bypass_checks=True, state='auto_accepted')
                successes += 1
            except exceptions.TransferStateSwitchError:
                errors += 1
        return successes, errors

    def reject(self, requester):
        for transfer in self:
            try:
                transfer.reject(requester=requester)
            except exceptions.TransferStateSwitchError:
                # Перемещение нельзя подтвердить – скорее всего оно уже перешло в expired. Игнорируем этот случай
                pass

    def expire(self):
        for transfer in self:
            try:
                transfer.expire()
            except exceptions.TransferStateSwitchError:
                # Перемещение нельзя подтвердить – скорее всего оно уже перешло в expired. Игнорируем этот случай
                pass

    def user(self):
        return self.filter(type='user')

    def user_group(self):
        return self.filter(type='user_group')

    def group(self):
        return self.filter(type__in=self.model.GROUP_TYPES)

    def related_for(self, group_transfer):
        qs = self.group().new().undecided().filter(source_path__startswith=group_transfer.source_path)
        return qs


class TransferManager(models.Manager.from_queryset(TransferQuerySet)):
    def create_user_group_transfers(self):
        group_transfers = self.group().unprocessed().select_related('group')
        for transfer in group_transfers:
            for member in transfer.group.members:
                self.get_or_create(
                    type='user_group',
                    state='undecided',
                    parent=transfer,
                    user=member,
                    group=transfer.group,
                    defaults={
                        'source_id': transfer.source_id,
                        'target_id': transfer.target_id,
                        'source_name': transfer.source_name,
                        'target_name': transfer.target_name,
                    },
                )
            transfer.state = 'undecided'
            transfer.save(update_fields=('state',))

    def autoresolve(self, from_date=None, to_date=None):
        from idm.core.models import Transfer

        log.info('Starting resolving transfers')
        with start_stop_actions(ACTION.TRANSFERS_STARTED_DECISION, ACTION.TRANSFERS_DECIDED) as manager, \
                log_duration(log, 'Deciding group transfers'):
            manager.on_failure({'data': {'status': 1}})
            manager.on_failure(lambda mngr: log.error('Cannot decide transfers', exc_info=True))

            report = {}
            for _type in (Transfer.TYPE_GROUP, Transfer.TYPE_USER):
                report.update({
                    f'{_type}_transfers_errors': 0,
                    f'{_type}_transfers_success': 0,
                    f'{_type}_transfers_accept': 0,
                    f'{_type}_transfers_reject': 0,
                })

            undecided = (
                self
                .undecided()
                .new()
                .filter(type__in=(Transfer.TYPE_GROUP, Transfer.TYPE_USER))
                .select_related('group', 'user')
                .order_by('-pk')
            )
            last_sync_date=transfers.get_last_sync_date()
            for transfer in undecided:
                try:
                    decision = transfer.get_decision(
                        from_date=from_date, to_date=to_date, last_sync_date=last_sync_date,
                    )
                    result = decision.result
                    # result ∈ {True, False, None}
                    if result is True:
                        transfer.accept(bypass_checks=True, state='auto_accepted', decision=decision)
                        report[f'{transfer.type}_transfers_success'] += 1
                        report[f'{transfer.type}_transfers_accept'] += 1
                    elif decision.result is False:
                        transfer.reject(bypass_checks=True, state='auto_rejected', decision=decision)
                        report[f'{transfer.type}_transfers_success'] += 1
                        report[f'{transfer.type}_transfers_reject'] += 1
                    else:
                        log.info('Transfers %s is left for manual decision', transfer.pk)
                except Exception:
                    log.exception('Could not decide transfer %s', transfer.pk)
                    report[f'{transfer.type}_transfers_errors'] += 1

            manager.on_success({
                'data': {
                    'status': 0,
                    'report': report
                }
            })
        log.info('Transfers are automagically resolved')
