from rest_framework import serializers
from .models import PollSurvey, Question, Response, ResponseDetail, Option
from tenants.models import Tenants
from django.db import transaction
from rest_framework import status


class OptionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Option
        fields = ["id", "option_text"]


class MinistryResponseDetailSerializer(serializers.ModelSerializer):
    """
    Serializer to display response details for a ministry officer.
    """

    question_text = serializers.ReadOnlyField(source="question.question_text")
    option_text = serializers.SerializerMethodField()

    def get_option_text(self, obj):
        # This method is called to get the value for 'option_text'
        return obj.option.option_text if obj.option else None

    class Meta:
        model = ResponseDetail
        fields = ["question_text", "answer_text", "option_text", "rating_value"]
        read_only_fields = [
            "question_text",
            "answer_text",
            "option_text",
            "rating_value",
        ]


class CitizenQuestionSerializer(serializers.ModelSerializer):
    options = OptionSerializer(many=True, read_only=True)

    class Meta:
        model = Question
        fields = ["id", "question_text", "question_type", "order", "options"]
        read_only_fields = fields  # All fields are read-only for citizens


class CitizenPollSurveySerializer(serializers.ModelSerializer):
    questions = CitizenQuestionSerializer(many=True, read_only=True)

    class Meta:
        model = PollSurvey
        fields = ["id", "title", "description", "type", "questions"]
        read_only_fields = fields  # All fields are read-only for citizens


class MinistryResponseSerializer(serializers.ModelSerializer):
    """
    Serializer to display a full response for a ministry officer.
    This includes nested details for each question.
    """

    user_email = serializers.ReadOnlyField(source="user.email")
    details = MinistryResponseDetailSerializer(many=True, read_only=True)

    class Meta:
        model = Response
        fields = ["id", "user_email", "submitted_at", "details"]
        read_only_fields = ["id", "user_email", "submitted_at", "details"]


class QuestionSerializer(serializers.ModelSerializer):
    """
    Serializer for the Question model. Used for both creating and retrieving questions.
    """

    options = OptionSerializer(many=True, required=False)

    class Meta:
        model = Question
        fields = ["id", "question_text", "question_type", "order", "options"]
        read_only_fields = ["id"]


class ResponseDetailSerializer(serializers.ModelSerializer):
    """
    Serializer for the ResponseDetail model. This handles the individual answers
    to a question within a response.
    """

    question = serializers.UUIDField()
    question_text = serializers.ReadOnlyField(source="question.question_text")
    option_text = serializers.ReadOnlyField(source="option.option_text")

    class Meta:
        model = ResponseDetail
        fields = [
            "question",
            "question_text",
            "answer_text",
            "option",
            "option_text",
            "rating_value",
        ]
        read_only_fields = ["question_text", "option_text"]

    def validate(self, data):
        """
        Custom validation to ensure the submitted data matches the question type.
        """
        question_id = data.get("question")
        try:
            # Find the actual Question object from the ID
            question = Question.objects.get(id=question_id)
        except Question.DoesNotExist:
            raise serializers.ValidationError({"question": "Question does not exist."})

        # Check the question type and the submitted data
        if question.question_type in ["multiple_choice", "checkbox"]:
            # For these types, 'option' must be provided, and 'answer_text'/'rating_value' should not be.
            if not data.get("option"):
                raise serializers.ValidationError(
                    {"option": "An option must be selected for this question type."}
                )
            if data.get("answer_text") or data.get("rating_value"):
                raise serializers.ValidationError(
                    "Cannot provide text or rating value for a choice-based question."
                )

        elif question.question_type == "text":
            # For text questions, 'answer_text' must be provided, and others should not be.
            if not data.get("answer_text"):
                raise serializers.ValidationError(
                    {"answer_text": "A text answer is required for this question."}
                )
            if data.get("option") or data.get("rating_value"):
                raise serializers.ValidationError(
                    "Cannot provide an option or rating value for a text question."
                )

        elif question.question_type == "rating":
            # For rating questions, 'rating_value' must be provided, and others should not be.
            if data.get("rating_value") is None:
                raise serializers.ValidationError(
                    {"rating_value": "A rating value is required for this question."}
                )
            if data.get("answer_text") or data.get("option"):
                raise serializers.ValidationError(
                    "Cannot provide a text answer or option for a rating question."
                )

        # Attach the full Question object to the validated data for use in .create()
        data["question"] = question
        return data

        read_only_fields = ["question_text", "option_text"]


class ResponseSerializer(serializers.ModelSerializer):
    details = ResponseDetailSerializer(many=True)

    class Meta:
        model = Response
        fields = ["id", "survey", "details"]
        read_only_fields = ["id"]

    # In your serializers.py file, within the ResponseSerializer class:

    def create(self, validated_data):
        details_data = validated_data.pop("details")
        with transaction.atomic():
            user = self.context.get("user")
            tenant = self.context.get("tenant")
            response = Response.objects.create(
                user=user, tenant=tenant, **validated_data
            )

            for detail_data in details_data:
                # The validated data from the nested serializer already contains
                # the correct Question and Option objects, not just UUIDs.
                ResponseDetail.objects.create(
                    response=response, tenant=tenant, **detail_data
                )
        return response


class PollSurveySerializer(serializers.ModelSerializer):
    """
    Serializer for the PollSurvey model. This is used by ministry officers
    to create and manage polls and surveys, including their questions.
    """

    questions = QuestionSerializer(many=True, required=False)
    created_by_username = serializers.ReadOnlyField(source="created_by.username")
    tenant_name = serializers.ReadOnlyField(source="tenant.name")
    response_count = serializers.ReadOnlyField()

    class Meta:
        model = PollSurvey
        fields = [
            "id",
            "tenant",
            "tenant_name",
            "title",
            "description",
            "type",
            "status",
            "start_date",
            "end_date",
            "created_by",
            "created_by_username",
            "created_at",
            "updated_at",
            "questions",
            "response_count",
        ]
        read_only_fields = [
            "id",
            "created_at",
            "updated_at",
            "created_by",
            "tenant_name",
        ]
        extra_kwargs = {
            "tenant": {
                "required": True
            }  # Explicitly allow the tenant to be provided in the request
        }

    def create(self, validated_data):
        questions_data = validated_data.pop("questions", [])
        request = self.context.get("request")
        if request and hasattr(request, "user"):
            validated_data["created_by"] = request.user

        with transaction.atomic():
            poll_survey = PollSurvey.objects.create(**validated_data)
            for question_data in questions_data:
                # Handle nested options data
                options_data = question_data.pop("options", [])
                question = Question.objects.create(
                    survey=poll_survey, tenant=poll_survey.tenant, **question_data
                )
                # Save options if they exist
                if options_data:
                    for option_data in options_data:
                        Option.objects.create(question=question, **option_data)

        return poll_survey

    def update(self, instance, validated_data):
        questions_data = validated_data.pop("questions", None)

        # Update PollSurvey fields
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()

        if questions_data is not None:
            # Clear existing questions and re-add them to handle edits
            instance.questions.all().delete()
            for question_data in questions_data:
                options_data = question_data.pop("options", [])
                question = Question.objects.create(
                    survey=instance, tenant=instance.tenant, **question_data
                )
                if options_data:
                    for option_data in options_data:
                        Option.objects.create(question=question, **option_data)

        return instance
