# coding: utf-8


import logging

from django.db.models import Q
from django.shortcuts import get_object_or_404

from idm.api.exceptions import BadRequest, Forbidden
from idm.api.frontend.base import FrontendApiResource
from idm.api.frontend.forms import TransferForm, TransferAcceptForm
from idm.core.exceptions import TransferStateSwitchError
from idm.core.models import Transfer


log = logging.getLogger(__name__)


class TransferResource(FrontendApiResource):
    """
    Ресурс перемещений
    """

    class Meta(FrontendApiResource.Meta):
        abstract = False
        object_class = Transfer
        queryset = Transfer.objects.all()
        resource_name = 'transfers'
        list_allowed_methods = ['get', 'post']
        detail_allowed_methods = ['get', 'post']
        fields = ['id', 'type', 'state', 'user', 'group',
                  'source', 'target',
                  'source_path', 'source_name', 'target_path', 'target_name']

    def get_object_list(self, request, **kwargs):
        requester = self.get_requester(request)
        if not requester.impersonated.has_perm('core.resolve_transfer'):
            return Transfer.objects.none()
        return super(TransferResource, self).get_object_list(request)

    def build_filters(self, request, filters=None):
        form = TransferForm(filters)
        if not form.is_valid():
            raise BadRequest(form.errors)

        query = form.cleaned_data
        qset_filters = Q()

        if query['type']:
            qset_filters &= Q(type__in=query['type'])

        if query['state']:
            qset_filters &= Q(state=query['state'])

        if query['user'] or query['group']:
            or_q = Q()

            if query['user']:
                or_q |= Q(user__in=[user.id for user in query['user']])

            if query['group']:
                or_q |= Q(group__in=[group.id for group in query['group']])

            qset_filters &= or_q

        return qset_filters

    def apply_filters(self, request, applicable_filters, **kwargs):
        return self.get_object_list(request).filter(applicable_filters)

    def post_list(self, request, **kwargs):
        data = self.deserialize(request, request.body)
        filters = self.build_filters(request, data)
        queryset = self.apply_filters(request, filters)
        form = TransferAcceptForm(data)
        if not form.is_valid():
            raise BadRequest(form.errors)

        requester = self.get_requester(request, data)
        if requester.allowed_systems is not None:
            raise Forbidden()

        data = form.cleaned_data
        successes = errors = 0
        for transfer in queryset.select_related('user', 'group'):
            method = transfer.accept if data['accept'] else transfer.reject
            try:
                method(requester=requester.impersonated)
                successes += 1
            except TransferStateSwitchError:
                # Перемещение нельзя подтвердить – скорее всего оно уже перешло в expired
                # Это легальная ситуация, просто игнорируем её
                errors += 1
        return self.create_response(request, {'successes': successes, 'errors': errors}, status=200)

    def post_detail(self, request, pk, **kwargs):
        data = self.deserialize(request, request.body)
        form = TransferAcceptForm(data)
        if not form.is_valid():
            raise BadRequest(form.errors)

        requester = self.get_requester(request, data)
        if requester.allowed_systems is not None:
            raise Forbidden()
        data = form.cleaned_data
        queryset = self.get_object_list(request)
        transfer = get_object_or_404(queryset.select_related('user'), pk=pk)
        method = transfer.accept if data['accept'] else transfer.reject

        try:
            method(requester=requester.impersonated)
        except TransferStateSwitchError:
            # Перемещение нельзя подтвердить – скорее всего оно уже перешло в expired
            # Это легальная ситуация, просто игнорируем её
            pass

        return self.create_response(request, None, status=204)
