from django.db import transaction
from django.utils.translation import ugettext as _

from openslides.poll.serializers import default_votes_validator
from openslides.utils.rest_api import (
    CharField,
    DictField,
    IntegerField,
    ModelSerializer,
    PrimaryKeyRelatedField,
    SerializerMethodField,
    ValidationError,
)

from .models import (
    Category,
    Motion,
    MotionLog,
    MotionPoll,
    MotionVersion,
    State,
    Workflow,
)


def validate_workflow_field(value):
    """
    Validator to ensure that the workflow with the given id exists.
    """
    if not Workflow.objects.filter(pk=value).exists():
        raise ValidationError({'detail': _('Workflow %(pk)d does not exist.') % {'pk': value}})


class CategorySerializer(ModelSerializer):
    """
    Serializer for motion.models.Category objects.
    """
    class Meta:
        model = Category
        fields = ('id', 'name', 'prefix',)


class StateSerializer(ModelSerializer):
    """
    Serializer for motion.models.State objects.
    """
    class Meta:
        model = State
        fields = (
            'id',
            'name',
            'action_word',
            'css_class',
            'required_permission_to_see',
            'allow_support',
            'allow_create_poll',
            'allow_submitter_edit',
            'versioning',
            'leave_old_version_active',
            'dont_set_identifier',
            'next_states',
            'workflow')


class WorkflowSerializer(ModelSerializer):
    """
    Serializer for motion.models.Workflow objects.
    """
    states = StateSerializer(many=True, read_only=True)
    first_state = PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = Workflow
        fields = ('id', 'name', 'states', 'first_state',)


class MotionLogSerializer(ModelSerializer):
    """
    Serializer for motion.models.MotionLog objects.
    """
    message = SerializerMethodField()

    class Meta:
        model = MotionLog
        fields = ('message_list', 'person', 'time', 'message',)

    def get_message(self, obj):
        """
        Concats the message parts to one string. Useful for smart template code.
        """
        return str(obj)


class MotionPollSerializer(ModelSerializer):
    """
    Serializer for motion.models.MotionPoll objects.
    """
    yes = SerializerMethodField()
    no = SerializerMethodField()
    abstain = SerializerMethodField()
    votes = DictField(
        child=IntegerField(min_value=-2, allow_null=True),
        write_only=True)
    has_votes = SerializerMethodField()

    class Meta:
        model = MotionPoll
        fields = (
            'id',
            'motion',
            'yes',
            'no',
            'abstain',
            'votesvalid',
            'votesinvalid',
            'votescast',
            'votes',
            'has_votes')
        validators = (default_votes_validator,)

    def __init__(self, *args, **kwargs):
        # The following dictionary is just a cache for several votes.
        self._votes_dicts = {}
        return super().__init__(*args, **kwargs)

    def get_yes(self, obj):