from django.core.exceptions import ObjectDoesNotExist

from staff.achievery import models

from .base import Condition, Role, ANONYMOUS
from .registry import library


class Owner(Role):
    """Абстрактный владелец"""

    def is_applicable(self):
        if isinstance(self.model, models.Achievement):
            achievement = self.model
        elif isinstance(self.model, models.GivenAchievement):
            try:
                achievement = self.model.achievement
            except ObjectDoesNotExist:
                return False
        else:
            return False

        try:
            return (
                achievement.owner_group.groupmembership_set
                .filter(staff=self.user).exists()
            )
        except ObjectDoesNotExist:
            return False

    @classmethod
    def get_query(cls, user, model_class):
        return {
            models.Achievement:
                Condition(models.Achievement.queries.owned_by(user)),
            models.GivenAchievement:
                Condition(models.GivenAchievement.queries.owned_by(user)),
        }.get(model_class, Condition(none=True))

    @classmethod
    def check_object(cls, role_registry, obj):
        if not isinstance(obj, (models.GivenAchievement, models.Achievement)):
            return False
        achievement_id = (
            obj.achievement_id
            if isinstance(obj, models.GivenAchievement) else
            obj.id
        )
        return role_registry.is_user_owner_for(achievement_id)


@library.register
class ActiveOwner(Owner):
    """Владелец активной ачивки"""

    fields = {
        models.Achievement: {
            'description': 'w',
            'description_html': 'w',
            'description_en': 'w',
            'description_html_en': 'w',
            'description_short': 'w',
            'description_short_en': 'w',
            'title': 'w',
            'title_en': 'w',
        },
        models.GivenAchievement: {
            'is_active': 'w',
            'comment': 'w',
            'comment_html': 'w',
            'level': 'w',
            'revision': 'w',
            'slot': 'w',
        },
    }

    def is_applicable(self):
        return (super(ActiveOwner, self).is_applicable()
                and self.model.is_active
                and not getattr(self.model, 'is_hidden', False))

    @classmethod
    def get_query(cls, user, model_class):
        if user is ANONYMOUS:
            return Condition(none=True)

        if model_class not in (models.Achievement, models.GivenAchievement):
            return Condition(none=True)
        owner_cond = super(ActiveOwner, cls).get_query(user, model_class)
        return owner_cond & Condition(model_class.queries.active)

    @classmethod
    def check_object(cls, role_registry, obj):
        if role_registry.user is ANONYMOUS:
            return False

        return (
            super(ActiveOwner, cls).check_object(role_registry, obj)
            and obj.is_active
        )


@library.register
class HiddenOwner(Owner):
    """Владелец скрытой ачивки"""

    fields = {
        models.Achievement: {
            'description': 'w',
            'description_html': 'w',
            'description_en': 'w',
            'description_html_en': 'w',
            'description_short': 'w',
            'description_short_en': 'w',
            'title': 'w',
            'title_en': 'w',
        },
        models.GivenAchievement: {
            'id': 'r',
            'comment': 'rw',
            'comment_html': 'rw',
            'is_hidden': 'r',
            'is_active': 'rw',
            'level': 'rw',
            'revision': 'rw',
            'slot': 'rw',
            'achievement': 'r',
            'person': 'r',
            'events': 'r',
            'created_at': 'r',
            'modified_at': 'r',
            'last_event_at': 'r',
        },
    }

    def is_applicable(self):
        return (super(HiddenOwner, self).is_applicable()
                and self.model.is_active
                and getattr(self.model, 'is_hidden', False))

    @classmethod
    def get_query(cls, user, model_class):
        if user is ANONYMOUS:
            return Condition(none=True)

        if model_class != models.GivenAchievement:
            return Condition(none=True)
        owner_cond = super(HiddenOwner, cls).get_query(user, model_class)
        return owner_cond & Condition(model_class.queries.hidden)

    @classmethod
    def check_object(cls, role_registry, obj):
        if role_registry.user is ANONYMOUS:
            return False

        return (
            isinstance(obj, models.GivenAchievement)
            and super(HiddenOwner, cls).check_object(role_registry, obj)
            and obj.is_hidden
        )


@library.register
class InactiveOwner(Owner):
    """Владелец неактивной ачивки"""

    fields = {
        models.GivenAchievement: {
            'id': 'r',
            'comment': 'rw',
            'comment_html': 'rw',
            'is_hidden': 'r',
            'is_active': 'rw',
            'level': 'r',
            'revision': 'rw',
            'slot': 'r',
            'achievement': 'r',
            'person': 'r',
            'events': 'r',
            'created_at': 'r',
            'modified_at': 'r',
            'last_event_at': 'r',
        },
    }

    def is_applicable(self):
        return (super(InactiveOwner, self).is_applicable()
                and not self.model.is_active)

    @classmethod
    def get_query(cls, user, model_class):
        if user is ANONYMOUS:
            return Condition(none=True)

        if model_class not in (models.Achievement, models.GivenAchievement):
            return Condition(none=True)
        owner_cond = super(InactiveOwner, cls).get_query(user, model_class)
        return owner_cond & Condition(model_class.queries.inactive)

    @classmethod
    def check_object(cls, role_registry, obj):
        if role_registry.user is ANONYMOUS:
            return False

        return (
            super(InactiveOwner, cls).check_object(role_registry, obj)
            and not obj.is_active
        )
