"""
Surveys serializers
"""

from rest_framework import serializers

from .models import (
    SurveyInstance,
    SurveyQuestion,
    SurveyResponse,
    SurveyTemplate,
    SurveyTracking,
    QuestionRoutingRule,
)


class SurveyQuestionSerializer(serializers.ModelSerializer):
    """Survey question serializer"""

    class Meta:
        model = SurveyQuestion
        fields = [
            "id",
            "survey_template",
            "text",
            "text_ar",
            "question_type",
            "order",
            "is_required",
            "is_base",
            "event_type",
            "choices_json",
            "is_conditional",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class QuestionRoutingRuleSerializer(serializers.ModelSerializer):
    """Routing rule serializer"""

    source_question_text = serializers.CharField(source="source_question.text", read_only=True)
    target_question_text = serializers.CharField(source="target_question.text", read_only=True, default=None)

    class Meta:
        model = QuestionRoutingRule
        fields = [
            "id",
            "survey_template",
            "source_question",
            "source_question_text",
            "operator",
            "value",
            "action",
            "target_question",
            "target_question_text",
            "order",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]


class SurveyTemplateSerializer(serializers.ModelSerializer):
    """Survey template serializer"""

    hospital_name = serializers.CharField(source="hospital.name", read_only=True)
    questions = SurveyQuestionSerializer(many=True, read_only=True)
    routing_rules = QuestionRoutingRuleSerializer(many=True, read_only=True)
    question_count = serializers.SerializerMethodField()

    class Meta:
        model = SurveyTemplate
        fields = [
            "id",
            "name",
            "name_ar",
            "hospital",
            "hospital_name",
            "survey_type",
            "scoring_method",
            "negative_threshold",
            "is_active",
            "instructions_en",
            "instructions_ar",
            "consent_text_en",
            "consent_text_ar",
            "requires_consent",
            "questions",
            "routing_rules",
            "question_count",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_question_count(self, obj):
        """Get number of questions"""
        return obj.get_question_count()


class SurveyResponseSerializer(serializers.ModelSerializer):
    """Survey response serializer"""

    question_text = serializers.SerializerMethodField()
    question_type = serializers.SerializerMethodField()

    class Meta:
        model = SurveyResponse
        fields = [
            "id",
            "survey_instance",
            "question",
            "question_text",
            "question_type",
            "numeric_value",
            "text_value",
            "choice_value",
            "created_at",
            "updated_at",
        ]
        read_only_fields = ["id", "created_at", "updated_at"]

    def get_question_text(self, obj):
        if obj.question:
            return obj.question.text
        return ""

    def get_question_type(self, obj):
        if obj.question:
            return obj.question.question_type
        return ""


class SurveyInstanceSerializer(serializers.ModelSerializer):
    """Survey instance serializer"""

    survey_template_name = serializers.SerializerMethodField()
    recipient_name = serializers.CharField(source="get_recipient_name", read_only=True)
    patient_name = serializers.CharField(source="patient.get_full_name", read_only=True)
    patient_mrn = serializers.CharField(source="patient.mrn", read_only=True)
    staff_name = serializers.CharField(source="staff.get_full_name", read_only=True)
    staff_email = serializers.EmailField(source="staff.email", read_only=True)
    responses = SurveyResponseSerializer(many=True, read_only=True)
    survey_url = serializers.SerializerMethodField()
    comment_analysis = serializers.JSONField(read_only=True)

    class Meta:
        model = SurveyInstance
        fields = [
            "id",
            "survey_template",
            "survey_template_name",
            "patient",
            "patient_name",
            "patient_mrn",
            "staff",
            "staff_name",
            "staff_email",
            "recipient_name",
            "journey_instance",
            "encounter_id",
            "delivery_channel",
            "recipient_phone",
            "recipient_email",
            "access_token",
            "token_expires_at",
            "survey_url",
            "status",
            "sent_at",
            "opened_at",
            "completed_at",
            "total_score",
            "is_negative",
            "comment",
            "comment_analyzed",
            "comment_analysis",
            "responses",
            "metadata",
            "created_at",
            "updated_at",
        ]
        read_only_fields = [
            "id",
            "access_token",
            "token_expires_at",
            "sent_at",
            "opened_at",
            "completed_at",
            "total_score",
            "is_negative",
            "created_at",
            "updated_at",
        ]

    def get_survey_template_name(self, obj):
        if obj.survey_template:
            return obj.survey_template.name
        return obj.metadata.get("patient_type", "Event-based Survey")

    def validate(self, data):
        """Validate that exactly one of patient or staff is set"""
        patient = data.get("patient")
        staff = data.get("staff")

        # If we're updating, get existing values
        if self.instance:
            patient = patient if patient is not None else self.instance.patient
            staff = staff if staff is not None else self.instance.staff

        if patient and staff:
            raise serializers.ValidationError(
                {
                    "patient": "Cannot specify both patient and staff for a survey",
                    "staff": "Cannot specify both patient and staff for a survey",
                }
            )

        if not patient and not staff:
            raise serializers.ValidationError(
                {
                    "patient": "Must specify either a patient or staff recipient",
                    "staff": "Must specify either a patient or staff recipient",
                }
            )

        return data

    def get_survey_url(self, obj):
        """Get survey URL"""
        return obj.get_survey_url()


class SurveySubmissionSerializer(serializers.Serializer):
    """
    Serializer for submitting survey responses.

    Used by public survey form.
    """

    responses = serializers.ListField(
        child=serializers.DictField(), help_text="Array of {question_id, numeric_value, text_value, choice_value}"
    )
    comment = serializers.CharField(
        required=False, allow_blank=True, allow_null=True, help_text="Optional patient comment about their experience"
    )

    def validate_responses(self, value):
        """Validate responses"""
        if not value:
            raise serializers.ValidationError("At least one response is required")

        for response in value:
            if "question_id" not in response:
                raise serializers.ValidationError("Each response must have question_id")

        return value

    def create(self, validated_data):
        """
        Create survey responses and calculate score.

        This is called when a patient submits the survey.
        Uses question_id to reference template questions.
        """
        survey_instance = self.context["survey_instance"]
        responses_data = validated_data["responses"]

        from apps.surveys.models import SurveyResponse, SurveyQuestion
        from django.utils import timezone

        for response_data in responses_data:
            question_id = response_data.get("question_id")
            choice_value = response_data.get("choice_value", "")
            numeric_value = response_data.get("numeric_value")
            text_value = response_data.get("text_value", "")

            if question_id:
                try:
                    question = SurveyQuestion.objects.get(id=question_id)
                    if choice_value and numeric_value is None:
                        for choice in question.choices_json or []:
                            if str(choice.get("value", "")) == str(choice_value):
                                if not text_value:
                                    text_value = choice.get("label", choice_value)
                                break
                        try:
                            numeric_value = float(choice_value)
                        except (ValueError, TypeError):
                            pass
                    SurveyResponse.objects.create(
                        survey_instance=survey_instance,
                        question=question,
                        numeric_value=numeric_value,
                        text_value=text_value,
                        choice_value=choice_value,
                        response_time_seconds=response_data.get("response_time_seconds"),
                    )
                except SurveyQuestion.DoesNotExist:
                    pass

        # Update survey instance
        survey_instance.status = "completed"
        survey_instance.completed_at = timezone.now()
        survey_instance.save()

        # Calculate score
        survey_instance.calculate_score()

        # Save optional comment if provided
        if "comment" in validated_data and validated_data["comment"]:
            survey_instance.comment = validated_data["comment"].strip()
            survey_instance.save(update_fields=["comment"])

        if survey_instance.is_negative:
            create_action_from_negative_survey.delay(str(survey_instance.id))

        return survey_instance


class SurveyTrackingSerializer(serializers.ModelSerializer):
    """
    Survey tracking events serializer.

    Tracks detailed engagement metrics for surveys.
    """

    survey_template_name = serializers.SerializerMethodField()
    recipient_name = serializers.CharField(source="survey_instance.get_recipient_name", read_only=True)
    patient_name = serializers.CharField(source="survey_instance.patient.get_full_name", read_only=True)
    staff_name = serializers.CharField(source="survey_instance.staff.get_full_name", read_only=True)

    class Meta:
        model = SurveyTracking
        fields = [
            "id",
            "survey_instance",
            "survey_template_name",
            "recipient_name",
            "patient_name",
            "staff_name",
            "event_type",
            "time_on_page",
            "total_time_spent",
            "current_question",
            "user_agent",
            "ip_address",
            "device_type",
            "browser",
            "country",
            "city",
            "metadata",
            "created_at",
        ]
        read_only_fields = ["id", "created_at"]

    def get_survey_template_name(self, obj):
        if obj.survey_instance.survey_template:
            return obj.survey_instance.survey_template.name
        return obj.survey_instance.metadata.get("patient_type", "Event-based Survey")


class SurveyInstanceAnalyticsSerializer(serializers.ModelSerializer):
    """
    Enhanced survey instance serializer with tracking analytics.
    """

    survey_template_name = serializers.SerializerMethodField()
    recipient_name = serializers.CharField(source="get_recipient_name", read_only=True)
    recipient_type = serializers.SerializerMethodField()
    patient_name = serializers.CharField(source="patient.get_full_name", read_only=True)
    patient_mrn = serializers.CharField(source="patient.mrn", read_only=True)
    staff_name = serializers.CharField(source="staff.get_full_name", read_only=True)
    staff_email = serializers.EmailField(source="staff.email", read_only=True)
    responses = SurveyResponseSerializer(many=True, read_only=True)
    survey_url = serializers.SerializerMethodField()
    tracking_events_count = serializers.SerializerMethodField()
    time_to_complete_minutes = serializers.SerializerMethodField()
    comment_analysis = serializers.JSONField(read_only=True)

    class Meta:
        model = SurveyInstance
        fields = [
            "id",
            "survey_template",
            "survey_template_name",
            "recipient_name",
            "recipient_type",
            "patient",
            "patient_name",
            "patient_mrn",
            "staff",
            "staff_name",
            "staff_email",
            "journey_instance",
            "encounter_id",
            "delivery_channel",
            "recipient_phone",
            "recipient_email",
            "access_token",
            "token_expires_at",
            "survey_url",
            "status",
            "sent_at",
            "opened_at",
            "completed_at",
            "open_count",
            "last_opened_at",
            "time_spent_seconds",
            "total_score",
            "is_negative",
            "comment",
            "comment_analyzed",
            "comment_analysis",
            "responses",
            "metadata",
            "tracking_events_count",
            "time_to_complete_minutes",
            "created_at",
            "updated_at",
        ]
        read_only_fields = [
            "id",
            "access_token",
            "token_expires_at",
            "sent_at",
            "opened_at",
            "completed_at",
            "open_count",
            "last_opened_at",
            "time_spent_seconds",
            "total_score",
            "is_negative",
            "tracking_events_count",
            "time_to_complete_minutes",
            "created_at",
            "updated_at",
        ]

    def get_survey_url(self, obj):
        """Get survey URL"""
        return obj.get_survey_url()

    def get_survey_template_name(self, obj):
        if obj.survey_template:
            return obj.survey_template.name
        return obj.metadata.get("patient_type", "Event-based Survey")

    def get_recipient_type(self, obj):
        """Get recipient type (patient or staff)"""
        return "staff" if obj.staff else "patient"

    def get_tracking_events_count(self, obj):
        """Get count of tracking events"""
        return obj.tracking_events.count()

    def get_time_to_complete_minutes(self, obj):
        """Calculate time to complete in minutes"""
        if obj.sent_at and obj.completed_at:
            time_diff = obj.completed_at - obj.sent_at
            return round(time_diff.total_seconds() / 60, 2)
        return None


class PublicSurveySerializer(serializers.ModelSerializer):
    """
    Public survey serializer for patient-facing survey form.

    Excludes sensitive information. Uses template questions.
    Includes routing rules for step-by-step navigation.
    """

    survey_name = serializers.SerializerMethodField()
    survey_name_ar = serializers.SerializerMethodField()
    questions = serializers.SerializerMethodField()
    routing_rules = serializers.SerializerMethodField()
    instructions_en = serializers.CharField(source="survey_template.instructions_en", read_only=True, default="")
    instructions_ar = serializers.CharField(source="survey_template.instructions_ar", read_only=True, default="")
    consent_text_en = serializers.CharField(source="survey_template.consent_text_en", read_only=True, default="")
    consent_text_ar = serializers.CharField(source="survey_template.consent_text_ar", read_only=True, default="")
    requires_consent = serializers.BooleanField(source="survey_template.requires_consent", read_only=True)
    hospital_name = serializers.CharField(source="survey_template.hospital.name", read_only=True, default="")

    class Meta:
        model = SurveyInstance
        fields = [
            "id",
            "survey_name",
            "survey_name_ar",
            "questions",
            "routing_rules",
            "instructions_en",
            "instructions_ar",
            "consent_text_en",
            "consent_text_ar",
            "requires_consent",
            "hospital_name",
            "status",
            "completed_at",
        ]
        read_only_fields = ["id", "status", "completed_at"]

    def get_survey_name(self, obj):
        if obj.survey_template:
            return obj.survey_template.name
        return "Patient Experience Survey"

    def get_survey_name_ar(self, obj):
        if obj.survey_template:
            return obj.survey_template.name_ar
        return ""

    def get_questions(self, obj):
        from django.db.models import Q

        patient_events = set(obj.metadata.get("event_types", []))
        qs = obj.survey_template.questions.filter(Q(is_base=True) | Q(event_type__in=patient_events)).order_by("order")
        return SurveyQuestionSerializer(qs, many=True).data

    def get_routing_rules(self, obj):
        if not obj.survey_template:
            return []
        rules = obj.survey_template.routing_rules.select_related("source_question", "target_question").order_by(
            "source_question__order", "order"
        )
        return QuestionRoutingRuleSerializer(rules, many=True).data
