# coding: utf-8
import datetime

from django.conf import settings
from django.db import models
from django.db.models import Manager, Q
from django.utils import timezone
from guardian.shortcuts import get_objects_for_user

from idm.core.constants.system import SYSTEM_GROUP_POLICY
from idm.framework.queryset import NestedValuesMixin
from idm.framework.requester import requesterify
from idm.utils.celery import parse_message
from idm.utils.mongo import get_mongo_db


class SystemQuerySet(NestedValuesMixin, models.QuerySet):
    def active(self):
        return self.filter(is_active=True)

    def inactive(self):
        return self.filter(is_active=False)

    def working(self):
        return self.filter(is_broken=False)

    def broken(self):
        return self.filter(is_broken=True)

    def operational(self):
        return self.active().working()

    def nondumb(self):
        return self.exclude(plugin_type='dumb')

    def dumb(self):
        return self.filter(plugin_type='dumb')

    def ready_for_sync(self):
        qs = self.active().filter(nodes__is_auto_updated=True, nodes__state='active').distinct()
        already_in_queue = self.get_systems_in_sync_celery_queue()
        systems = [system for system in qs if system.is_ready_for_tree_sync() and system.slug not in already_in_queue]
        return systems

    def get_systems_in_sync_celery_queue(self):
        mongo_db = get_mongo_db()
        systems = set()
        for message in mongo_db.messages.find():
            try:
                body = parse_message(message)
            except Exception:
                continue
            task = body.get('task')
            if task != 'idm.core.tasks.everysync.EverySync':
                continue
            kwargs = body['kwargs']
            step = kwargs.get('step')
            if step != 'sync_nodes':
                continue
            systems.add(kwargs.get('system_slug'))
        return systems

    def unchecked(self, since=None):
        if since is None:
            since = timezone.now() - datetime.timedelta(days=settings.IDM_CHECK_AND_RESOLVE_ALERT_THERSHOLD_DAYS)
        return self.filter(metainfo__last_check_inconsistencies_finish__lt=since)

    def get_systems_with_group_sync_policy(self):
        return self.filter(group_policy__in=SYSTEM_GROUP_POLICY.AWARE_OF_MEMBERSHIPS)


class SystemManager(Manager.from_queryset(SystemQuerySet)):
    def get_operational(self):
        return self.operational()

    def get_idm_system(self):
        return self.get(slug=settings.IDM_SYSTEM_SLUG)

    def permitted_for(self, requester, permission):
        queryset = super(SystemManager, self).get_queryset()

        return queryset.filter(self.permitted_query(requester, permission))

    def permitted_query(self, requester, permission, **kwargs):
        from idm.core.models import InternalRole

        requester = requesterify(requester)

        qs = get_objects_for_user(requester.impersonated, permission,
                                  klass=InternalRole, use_groups=False, with_superuser=False)

        if requester.allowed_systems is None and qs.filter(node=None).exists():
            return Q()

        if requester.allowed_systems is not None:
            qs = qs.filter(node__system__in=requester.allowed_systems)

        return Q(id__in=qs.values('node__system').distinct())
