from django.contrib.auth import get_user_model
from django.contrib.humanize.templatetags import humanize
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from .forms import TicketForm
from .lib import format_time_spent
from .models import CustomField, FollowUp, FollowUpAttachment, Ticket
from .user import HelpdeskUser
from .update_ticket import update_ticket


class DatatablesTicketSerializer(serializers.ModelSerializer):
    """
    A serializer for the Ticket model, returns data in the format as required by
    datatables for ticket_list.html. Called from staff.datatables_ticket_list.
    """
    ticket = serializers.SerializerMethodField()
    assigned_to = serializers.SerializerMethodField()
    submitter = serializers.SerializerMethodField()
    created = serializers.SerializerMethodField()
    due_date = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()
    row_class = serializers.SerializerMethodField()
    time_spent = serializers.SerializerMethodField()
    queue = serializers.SerializerMethodField()
    kbitem = serializers.SerializerMethodField()

    class Meta:
        model = Ticket
        # fields = '__all__'
        fields = ('ticket', 'id', 'priority', 'title', 'queue', 'status',
                  'created', 'due_date', 'assigned_to', 'submitter', 'row_class',
                  'time_spent', 'kbitem')

    def get_queue(self, obj):
        return {"title": obj.queue.title, "id": obj.queue.id}

    def get_ticket(self, obj):
        return str(obj.id) + " " + obj.ticket

    def get_status(self, obj):
        return obj.get_status

    def get_created(self, obj):
        return humanize.naturaltime(obj.created)

    def get_due_date(self, obj):
        return humanize.naturaltime(obj.due_date)

    def get_assigned_to(self, obj):
        if obj.assigned_to:
            if obj.assigned_to.get_full_name():
                return obj.assigned_to.get_full_name()
            elif obj.assigned_to.email:
                return obj.assigned_to.email
            else:
                return obj.assigned_to.username
        else:
            return "None"

    def get_submitter(self, obj):
        return obj.submitter_email

    def get_time_spent(self, obj):
        return format_time_spent(obj.time_spent)

    def get_row_class(self, obj):
        return obj.get_priority_css_class

    def get_kbitem(self, obj):
        return obj.kbitem.title if obj.kbitem else ""


class FollowUpAttachmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = FollowUpAttachment
        fields = ('id', 'followup', 'file', 'filename', 'mime_type', 'size')


class FollowUpSerializer(serializers.ModelSerializer):
    followupattachment_set = FollowUpAttachmentSerializer(
        many=True, read_only=True)
    attachments = serializers.ListField(
        child=serializers.FileField(),
        write_only=True,
        required=False
    )
    date = serializers.DateTimeField(read_only=True)

    class Meta:
        model = FollowUp
        fields = (
            'id', 'ticket', 'user', 'title', 'comment', 'public', 'new_status',
            'time_spent', 'attachments', 'followupattachment_set', 'date', 'message_id',
        )

    def create(self, validated_data):
        if validated_data["user"]:
            user = validated_data["user"]
        else:
            user = self.context['request'].user
        return update_ticket(
            user=user,
            ticket=validated_data["ticket"],
            title=validated_data.get("title", None),
            comment=validated_data.get("comment", ""),
            files=validated_data.get("attachments", None),
            public=validated_data.get("public", False),
            new_status=validated_data.get("new_status", None),
            time_spent=validated_data.get("time_spent", None),
        )


class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)

    class Meta:
        model = get_user_model()
        fields = ('first_name', 'last_name', 'username', 'email', 'password')

    def create(self, validated_data):
        user = super(UserSerializer, self).create(validated_data)
        user.is_active = True
        user.set_password(validated_data['password'])
        user.save()
        return user


class BaseTicketSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Add custom fields
        for field in CustomField.objects.all():
            self.fields['custom_%s' % field.name] = field.build_api_field()


class PublicTicketListingSerializer(BaseTicketSerializer):
    """
    A serializer to be used by the public API for listing tickets. Don't expose private fields here!
    """
    ticket = serializers.SerializerMethodField()
    submitter = serializers.SerializerMethodField()
    created = serializers.SerializerMethodField()
    due_date = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()
    queue = serializers.SerializerMethodField()
    kbitem = serializers.SerializerMethodField()
    secret_key = serializers.CharField(read_only=True)

    class Meta:
        model = Ticket
        # fields = '__all__'
        fields = ('ticket', 'id', 'title', 'queue', 'status',
                  'created', 'due_date', 'submitter', 'kbitem', 'secret_key')

    def get_queue(self, obj):
        return {"title": obj.queue.title, "id": obj.queue.id}

    def get_ticket(self, obj):
        return str(obj.id) + " " + obj.ticket

    def get_status(self, obj):
        return obj.get_status

    def get_created(self, obj):
        return humanize.naturaltime(obj.created)

    def get_due_date(self, obj):
        return humanize.naturaltime(obj.due_date)

    def get_submitter(self, obj):
        return obj.submitter_email

    def get_kbitem(self, obj):
        return obj.kbitem.title if obj.kbitem else ""


# class TicketSerializer(BaseTicketSerializer):
#     followup_set = FollowUpSerializer(many=True, read_only=True)
#     attachment = serializers.FileField(write_only=True, required=False)

#     class Meta:
#         model = Ticket
#         fields = (
#             'id', 'queue', 'title', 'description', 'resolution', 'submitter_email', 'assigned_to', 'status', 'on_hold',
#             'priority', 'due_date', 'merged_to', 'attachment', 'followup_set'
#         )

#     def create(self, validated_data):
#         """ Use TicketForm to validate and create ticket """
#         queues = HelpdeskUser(self.context['request'].user).get_queues()
#         queue_choices = [(q.id, q.title) for q in queues]
#         data = validated_data.copy()
#         data['body'] = data['description']
#         # TicketForm needs id for ForeignKey (not the instance themselves)
#         data['queue'] = data['queue'].id
#         if data.get('assigned_to'):
#             data['assigned_to'] = data['assigned_to'].id
#         if data.get('merged_to'):
#             data['merged_to'] = data['merged_to'].id

#         files = {'attachment': data.pop('attachment', None)}

#         ticket_form = TicketForm(
#             data=data, files=files, queue_choices=queue_choices)
#         if ticket_form.is_valid():
#             ticket = ticket_form.save(user=self.context['request'].user)
#             ticket.set_custom_field_values()
#             return ticket

#         raise ValidationError(ticket_form.errors)

#     def update(self, instance, validated_data):
#         instance = super().update(instance, validated_data)
#         instance.save_custom_field_values(validated_data)
#         return instance



from django.contrib.auth import get_user_model
from django.contrib.humanize.templatetags import humanize
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from .forms import TicketForm
from .lib import format_time_spent
from .models import CustomField, FollowUp, FollowUpAttachment, Ticket
from .user import HelpdeskUser
from .update_ticket import update_ticket


class DatatablesTicketSerializer(serializers.ModelSerializer):
    """
    A serializer for the Ticket model, returns data in the format as required by
    datatables for ticket_list.html. Called from staff.datatables_ticket_list.
    """
    ticket = serializers.SerializerMethodField()
    assigned_to = serializers.SerializerMethodField()
    submitter = serializers.SerializerMethodField()
    created = serializers.SerializerMethodField()
    due_date = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()
    row_class = serializers.SerializerMethodField()
    time_spent = serializers.SerializerMethodField()
    queue = serializers.SerializerMethodField()
    kbitem = serializers.SerializerMethodField()

    class Meta:
        model = Ticket
        # fields = '__all__'
        fields = ('ticket', 'id', 'priority', 'title', 'queue', 'status',
                  'created', 'due_date', 'assigned_to', 'submitter', 'row_class',
                  'time_spent', 'kbitem')

    def get_queue(self, obj):
        return {"title": obj.queue.title, "id": obj.queue.id}

    def get_ticket(self, obj):
        return str(obj.id) + " " + obj.ticket

    def get_status(self, obj):
        return obj.get_status

    def get_created(self, obj):
        return humanize.naturaltime(obj.created)

    def get_due_date(self, obj):
        return humanize.naturaltime(obj.due_date)

    def get_assigned_to(self, obj):
        if obj.assigned_to:
            if obj.assigned_to.get_full_name():
                return obj.assigned_to.get_full_name()
            elif obj.assigned_to.email:
                return obj.assigned_to.email
            else:
                return obj.assigned_to.username
        else:
            return "None"

    def get_submitter(self, obj):
        return obj.submitter_email

    def get_time_spent(self, obj):
        return format_time_spent(obj.time_spent)

    def get_row_class(self, obj):
        return obj.get_priority_css_class

    def get_kbitem(self, obj):
        return obj.kbitem.title if obj.kbitem else ""


class FollowUpAttachmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = FollowUpAttachment
        fields = ('id', 'followup', 'file', 'filename', 'mime_type', 'size')


class FollowUpSerializer(serializers.ModelSerializer):
    followupattachment_set = FollowUpAttachmentSerializer(
        many=True, read_only=True)
    attachments = serializers.ListField(
        child=serializers.FileField(),
        write_only=True,
        required=False
    )
    date = serializers.DateTimeField(read_only=True)

    class Meta:
        model = FollowUp
        fields = (
            'id', 'ticket', 'user', 'title', 'comment', 'public', 'new_status',
            'time_spent', 'attachments', 'followupattachment_set', 'date', 'message_id',
        )

    def create(self, validated_data):
        if validated_data["user"]:
            user = validated_data["user"]
        else:
            user = self.context['request'].user
        return update_ticket(
            user=user,
            ticket=validated_data["ticket"],
            title=validated_data.get("title", None),
            comment=validated_data.get("comment", ""),
            files=validated_data.get("attachments", None),
            public=validated_data.get("public", False),
            new_status=validated_data.get("new_status", None),
            time_spent=validated_data.get("time_spent", None),
        )


class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)

    class Meta:
        model = get_user_model()
        fields = ('first_name', 'last_name', 'username', 'email', 'password')

    def create(self, validated_data):
        user = super(UserSerializer, self).create(validated_data)
        user.is_active = True
        user.set_password(validated_data['password'])
        user.save()
        return user


class BaseTicketSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Add custom fields
        for field in CustomField.objects.all():
            self.fields['custom_%s' % field.name] = field.build_api_field()


class PublicTicketListingSerializer(BaseTicketSerializer):
    """
    A serializer to be used by the public API for listing tickets. Don't expose private fields here!
    """
    ticket = serializers.SerializerMethodField()
    submitter = serializers.SerializerMethodField()
    created = serializers.SerializerMethodField()
    due_date = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()
    queue = serializers.SerializerMethodField()
    kbitem = serializers.SerializerMethodField()
    secret_key = serializers.CharField(read_only=True)

    class Meta:
        model = Ticket
        # fields = '__all__'
        fields = ('ticket', 'id', 'title', 'queue', 'status',
                  'created', 'due_date', 'submitter', 'kbitem', 'secret_key')

    def get_queue(self, obj):
        return {"title": obj.queue.title, "id": obj.queue.id}

    def get_ticket(self, obj):
        return str(obj.id) + " " + obj.ticket

    def get_status(self, obj):
        return obj.get_status

    def get_created(self, obj):
        return humanize.naturaltime(obj.created)

    def get_due_date(self, obj):
        return humanize.naturaltime(obj.due_date)

    def get_submitter(self, obj):
        return obj.submitter_email

    def get_kbitem(self, obj):
        return obj.kbitem.title if obj.kbitem else ""


class TicketSerializer(BaseTicketSerializer):
    followup_set = FollowUpSerializer(many=True, read_only=True)
    attachment = serializers.FileField(write_only=True, required=False)

    class Meta:
        model = Ticket
        fields = (
            'id',  'title', 'description', 'resolution', 'submitter_email', 'assigned_to', 'status', 'on_hold',
            'priority', 'due_date', 'merged_to', 'attachment', 'followup_set'
        )

    def create(self, validated_data):
        """ Use TicketForm to validate and create ticket """
        queues = HelpdeskUser(self.context['request'].user).get_queues()
        queue_choices = [(q.id, q.title) for q in queues]
        data = validated_data.copy()
        data['body'] = data['description']
        # TicketForm needs id for ForeignKey (not the instance themselves)
        data['queue'] = data['queue'].id
        if data.get('assigned_to'):
            data['assigned_to'] = data['assigned_to'].id
        if data.get('merged_to'):
            data['merged_to'] = data['merged_to'].id

        files = {'attachment': data.pop('attachment', None)}

        ticket_form = TicketForm(
            data=data, files=files, queue_choices=queue_choices)
        if ticket_form.is_valid():
            ticket = ticket_form.save(user=self.context['request'].user)
            ticket.set_custom_field_values()
            return ticket

        raise ValidationError(ticket_form.errors)

    def update(self, instance, validated_data):
        instance = super().update(instance, validated_data)
        instance.save_custom_field_values(validated_data)
        return instance
