# -*- coding: utf-8 -*-
#
from collections import defaultdict
from django.db.models import F, Value, Model
from django.db.models.signals import m2m_changed
from django.db.models.functions import Concat

from common.utils import get_logger
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.utils import current_org
from .. import models, serializers

__all__ = [
    'SystemUserAssetRelationViewSet', 'SystemUserNodeRelationViewSet',
    'SystemUserUserRelationViewSet', 'BaseRelationViewSet',
]

logger = get_logger(__name__)


class RelationMixin:
    model: Model

    def get_queryset(self):
        queryset = self.model.objects.all()
        if not current_org.is_root():
            org_id = current_org.org_id()
            queryset = queryset.filter(systemuser__org_id=org_id)

        queryset = queryset.annotate(systemuser_display=Concat(
            F('systemuser__name'), Value('('),
            F('systemuser__username'), Value(')')
        ))
        return queryset

    def send_post_add_signal(self, instance):
        if not isinstance(instance, list):
            instance = [instance]

        system_users_objects_map = defaultdict(list)
        model, object_field = self.get_objects_attr()

        for i in instance:
            _id = getattr(i, object_field).id
            system_users_objects_map[i.systemuser].append(_id)

        sender = self.get_sender()
        for system_user, object_ids in system_users_objects_map.items():
            logger.debug('System user relation changed, send m2m_changed signals')
            m2m_changed.send(
                sender=sender, instance=system_user, action='post_add',
                reverse=False, model=model, pk_set=set(object_ids)
            )

    def get_sender(self):
        return self.model

    def get_objects_attr(self):
        return models.Asset, 'asset'

    def perform_create(self, serializer):
        instance = serializer.save()
        self.send_post_add_signal(instance)


class BaseRelationViewSet(RelationMixin, OrgBulkModelViewSet):
    perm_model = models.SystemUser


class SystemUserAssetRelationViewSet(BaseRelationViewSet):
    perm_model = models.AuthBook
    serializer_class = serializers.SystemUserAssetRelationSerializer
    model = models.SystemUser.assets.through
    filterset_fields = [
        'id', 'asset', 'systemuser',
    ]
    search_fields = [
        "id", "asset__hostname", "asset__ip",
        "systemuser__name", "systemuser__username",
    ]

    def get_objects_attr(self):
        return models.Asset, 'asset'

    def get_queryset(self):
        queryset = super().get_queryset()
        queryset = queryset.annotate(
            asset_display=Concat(
                F('asset__hostname'), Value('('),
                F('asset__ip'), Value(')')
            )
        )
        return queryset


class SystemUserNodeRelationViewSet(BaseRelationViewSet):
    serializer_class = serializers.SystemUserNodeRelationSerializer
    model = models.SystemUser.nodes.through
    filterset_fields = [
        'id', 'node', 'systemuser',
    ]
    search_fields = [
        "node__value", "systemuser__name", "systemuser__username"
    ]

    def get_objects_attr(self):
        return models.Node, 'node'

    def get_queryset(self):
        queryset = super().get_queryset()
        queryset = queryset \
            .annotate(node_key=F('node__key'))
        return queryset


class SystemUserUserRelationViewSet(BaseRelationViewSet):
    serializer_class = serializers.SystemUserUserRelationSerializer
    model = models.SystemUser.users.through
    filterset_fields = [
        'id', 'user', 'systemuser',
    ]
    search_fields = [
        "user__username", "user__name",
        "systemuser__name", "systemuser__username",
    ]

    def get_objects_attr(self):
        from users.models import User
        return User, 'user'

    def get_queryset(self):
        queryset = super().get_queryset()
        queryset = queryset.annotate(
            user_display=Concat(
                F('user__name'), Value('('),
                F('user__username'), Value(')')
            )
        )
        return queryset