# coding: utf-8

from procu.api import models
from procu.api.enquiry.access.serializers import AllowQuoteComments
from procu.api.enums import ACCESS_SOURCE
from procu.api.utils import dict_diff
from procu.rest import serializers


class UserSerializer(serializers.ModelSerializer):
    full_name = serializers.CharField()

    class Meta:
        model = models.User
        fields = ('id', 'username', 'full_name', 'is_staff')


class AccessSerializer(serializers.ModelSerializer):
    user = UserSerializer()
    allow_quote_comments = AllowQuoteComments()

    class Meta:
        model = models.EnquiryAccess
        fields = ('id', 'user', 'allow_quote_comments', 'is_subscribed')


class AccessSnapshot:
    def __init__(self, enquiry_id, accesses):
        self.enquiry_id = enquiry_id
        self.accesses = accesses

    @classmethod
    def create(cls, enquiry_id):

        accesses = []

        qs = (
            models.EnquiryAccess.objects.select_related('user')
            .filter(
                sources__contains=[ACCESS_SOURCE.ACCESS], enquiry_id=enquiry_id
            )
            .order_by('id')
        )

        for obj in qs:
            access = AccessSerializer(obj).data
            accesses.append(access)

        return AccessSnapshot(enquiry_id, accesses)

    def diff(self, new: 'AccessSnapshot'):
        assert new.enquiry_id == self.enquiry_id

        diff = {'accesses': []}

        dummy = dict.fromkeys(
            ('id', 'user', 'is_subscribed', 'allow_quote_comments')
        )

        old_access_map = {access['id']: access for access in self.accesses}

        for new_access in new.accesses:
            new_access_id = new_access.get('id')

            if new_access_id in old_access_map:
                # Updated access
                old_access = old_access_map.pop(new_access_id)
                pdiff = dict_diff(
                    old_access,
                    new_access,
                    fields=('user', 'is_subscribed', 'allow_quote_comments'),
                )
                if pdiff:
                    diff['accesses'].append(pdiff)

            else:
                # Created access
                diff['accesses'].append(dict_diff(dummy, new_access))

        # Deleted accesses
        for access in old_access_map.values():
            diff['accesses'].append(dict_diff(access, dummy))

        return diff if diff['accesses'] else {}
