from staff.groups.objects.controller import (
    ServiceGroupCtl,
    ServiceRoleGroupCtl,
)
from staff.groups.service.constants import TERMINATED_SERVICE_STATES
from staff.groups.service.helpers import get_service_root


class Command(object):

    def message(self):
        raise NotImplementedError

    def run(self):
        raise NotImplementedError

    def useful(self):
        return True


class CreateMember(Command):

    def __init__(self, service_id, group, person):
        super(CreateMember, self).__init__()
        self.group = group
        self.person = person
        self.service_id = service_id

    def message(self):
        return 'Created membership {person} in {group}'.format(
            person=self.person, group=self.group
        )

    def run(self):
        ServiceGroupCtl(self.group).add_member(new_member=self.person)


class DeleteMember(Command):

    def __init__(self, service_id, member):
        super(DeleteMember, self).__init__()
        self.member = member
        self.service_id = service_id

    def message(self):
        return 'Deleted membership {person} in {group}'.format(
            person=self.member.staff, group=self.member.group
        )

    def run(self):
        ServiceGroupCtl(self.member.group).delete_member(self.member.staff)


class ServiceGroupMixin(object):

    ctl_class = ServiceGroupCtl

    def __init__(self, service_id, data):
        self.data = data
        self.service_id = service_id
        self.parent = get_service_root()

    def command_submission(self):
        return 'for service {service}'.format(service=self.service_id)

    @property
    def group_data(self):
        data = {
            'type': self.ctl_class.type,
            'code': self.data['slug'].lower(),
            'service_id': self.service_id,
            'role_scope_id': None,
            'native_lang': 'ru',
            'name': self.data['name'],
            'name_en': self.data['name_en'],
            'description': self.data['description'] or '',
            'parent': self.parent,
            'parent_service_id': self.data['parent'] and self.data['parent']['id'],
            'service_tags': ','.join(
                sorted(
                    tag['slug'].lower()
                    for tag in self.data['tags']
                )
            ),
        }

        return data


class ServiceRoleGroupMixin(object):

    ctl_class = ServiceRoleGroupCtl

    def __init__(self, service_group, role_scope):
        self.parent = service_group
        self.service_id = service_group.service_id
        self.role_scope_id = role_scope['slug']
        self.role_scope = role_scope

    def command_submission(self):
        return 'for role scope {scope} in service {service}'.format(
            scope=self.role_scope_id,
            service=self.service_id,
        )

    @property
    def group_data(self):
        name = self.role_scope['name']
        if not name:
            name = self.role_scope_id.replace('_', ' ').title()

        return {
            'type': self.ctl_class.type,
            'code': self.role_scope_id,
            'service_id': None,
            'role_scope_id': self.role_scope_id,
            'name': '{0} ({1})'.format(name, self.parent.name),
            'description': '',
            'parent': self.parent,
            'parent_service_id': None,
            'service_tags': '',
        }


class CreateGroup(Command):

    def __init__(self, *args, **kwargs):
        super(CreateGroup, self).__init__(*args, **kwargs)

    def message(self):
        return 'Created group {0}'.format(self.command_submission())

    def run(self):
        self.ctl_class().create_filled(
            parent=self.parent, data=self.group_data
        )


class UpdateGroup(Command):

    def __init__(self, group, state, *args, **kwargs):
        super(UpdateGroup, self).__init__(*args, **kwargs)
        self.group = group
        self.state = state

    def message(self):
        return 'Updated group {name} {submission}'.format(
            name=self.group.name,
            submission=self.command_submission(),
        )

    def run(self):
        self.ctl_class(group=self.group).update(self.group_data, enable=self._enabled)

    def useful(self):
        group_data = self.group_data

        has_changes = (
            self.group.name != group_data['name']
            or self.group.code != group_data.get('code', self.group.code)
            or self.group.description != group_data['description']
            or (self.group.intranet_status != 0) != self._enabled
            or self.group.parent != self.parent
        )

        return has_changes

    @property
    def _enabled(self):
        return self.state not in TERMINATED_SERVICE_STATES


class DeleteGroup(Command):

    def message(self):
        return 'Deleted group {name} {submission}'.format(
            name=self.group.name,
            submission=self.command_submission(),
        )

    def run(self):
        self.ctl_class(self.group).delete()


class CreateServiceGroup(CreateGroup, ServiceGroupMixin):
    """Создает сервисную группу"""

    def __init__(self, service_id, data):
        CreateGroup.__init__(self, service_id=service_id, data=data)
        ServiceGroupMixin.__init__(self, service_id, data)


class UpdateServiceGroup(UpdateGroup, ServiceGroupMixin):
    """Обновляет сервисную группу"""

    def __init__(self, group, service_id, data):
        UpdateGroup.__init__(self, group, state=data['state'], service_id=service_id, data=data)
        ServiceGroupMixin.__init__(self, service_id, data)

    def useful(self):
        group_data = self.group_data

        has_changes = (
            super().useful()
            or self.group.native_lang != group_data['native_lang']
            or self.group.name_en != group_data['name_en']
            or self.group.service_tags != group_data['service_tags']
            or self.group.parent_service_id != group_data['parent_service_id']
            or self.group.type != group_data['type']
            or self.group.role_scope_id != group_data['role_scope_id']
        )
        return has_changes


class DeleteServiceGroup(DeleteGroup, ServiceGroupMixin):
    """Удаляет сервисную группу"""

    def __init__(self, group):
        self.group = group
        self.service_id = group.service_id


class CreateServiceRoleGroup(CreateGroup, ServiceRoleGroupMixin):
    """Создает ролевую группу в сервисной"""

    def __init__(self, service_group, role_scope):
        CreateGroup.__init__(self, service_group=service_group, role_scope=role_scope)
        ServiceRoleGroupMixin.__init__(self, service_group, role_scope)


class UpdateServiceRoleGroup(UpdateGroup, ServiceRoleGroupMixin):
    """Обновляет ролевую группу в сервисной"""

    def __init__(self, group, service_group, role_scope, state):
        UpdateGroup.__init__(self, group, state=state, service_group=service_group, role_scope=role_scope)
        ServiceRoleGroupMixin.__init__(self, service_group, role_scope)

    def useful(self):
        group_data = self.group_data

        has_changes = (
            super().useful()
            or self.group.service_tags != group_data['service_tags']
            or self.group.parent_service_id != group_data['parent_service_id']
            or self.group.type != group_data['type']
            or self.group.service_id != group_data['service_id']
            or self.group.role_scope_id != group_data['role_scope_id']
        )
        return has_changes


class DeleteServiceRoleGroup(DeleteGroup, ServiceRoleGroupMixin):
    """Удаляет ролевую группу"""

    def __init__(self, group):
        self.group = group
        self.service_id = group.parent.service_id
        self.role_scope_id = group.role_scope_id
