import datetime
from django import forms
from django.forms import ModelMultipleChoiceField
from django.contrib.auth.models import User
from generic.widgets import UserSearchWidget
from .models import Survey, SurveyQuestion, SurveyResponse, SurveyAnswer

class SurveyForm(forms.ModelForm):
    author = ModelMultipleChoiceField(
        queryset=User.objects.all(),
        widget=UserSearchWidget(),
        required=False,
        help_text="Users who can view and manage this survey when it is set to private."
    )

    class Meta:
        model = Survey
        fields = [
            "name",
            "description",
            "before_text",
            "after_text",
            "active",
            "anonymous",
            "authors_only",
            "author"
        ]
        widgets = {
            "description": forms.Textarea(attrs={"rows": 3}),
            "before_text": forms.Textarea(attrs={"rows": 3, "placeholder": "Instructions shown before the survey starts..."}),
            "after_text": forms.Textarea(attrs={"rows": 3, "placeholder": "Thank you message shown after submission..."}),
        }


class SurveyQuestionForm(forms.ModelForm):
    # Form-only fields for validation rules
    min_value = forms.IntegerField(required=False, label="Minimum Value (Integer)")
    max_value = forms.IntegerField(required=False, label="Maximum Value (Integer)")
    min_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date"}), label="Minimum Date")
    max_date = forms.DateField(required=False, widget=forms.DateInput(attrs={"type": "date"}), label="Maximum Date")

    class Meta:
        model = SurveyQuestion
        fields = ["text", "question_type", "choices", "required", "position"]
        widgets = {
            "choices": forms.Textarea(attrs={"rows": 4, "placeholder": "Enter each choice on a new line"}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Populate initial values for validation fields from validation_rules dict
        if self.instance and self.instance.pk and self.instance.validation_rules:
            rules = self.instance.validation_rules
            self.fields["min_value"].initial = rules.get("min_value")
            self.fields["max_value"].initial = rules.get("max_value")
            
            min_date_val = rules.get("min_date")
            if min_date_val:
                try:
                    self.fields["min_date"].initial = datetime.date.fromisoformat(min_date_val)
                except ValueError:
                    pass
            
            max_date_val = rules.get("max_date")
            if max_date_val:
                try:
                    self.fields["max_date"].initial = datetime.date.fromisoformat(max_date_val)
                except ValueError:
                    pass

    def save(self, commit=True):
        instance = super().save(commit=False)
        # Build validation_rules dict
        rules = {}
        min_val = self.cleaned_data.get("min_value")
        max_val = self.cleaned_data.get("max_value")
        min_dt = self.cleaned_data.get("min_date")
        max_dt = self.cleaned_data.get("max_date")

        if min_val is not None:
            rules["min_value"] = min_val
        if max_val is not None:
            rules["max_value"] = max_val
        if min_dt is not None:
            rules["min_date"] = min_dt.isoformat()
        if max_dt is not None:
            rules["max_date"] = max_dt.isoformat()

        instance.validation_rules = rules
        if commit:
            instance.save()
        return instance


class SurveyTakeForm(forms.Form):
    def __init__(self, *args, **kwargs):
        self.survey = kwargs.pop("survey")
        self.questions = list(self.survey.questions.all())
        super().__init__(*args, **kwargs)
        
        for q in self.questions:
            field_name = f"question_{q.pk}"
            if q.question_type == SurveyQuestion.QuestionType.TEXT:
                self.fields[field_name] = forms.CharField(
                    label=q.text,
                    required=q.required,
                    widget=forms.Textarea(attrs={"rows": 3, "class": "form-control"})
                )
            elif q.question_type == SurveyQuestion.QuestionType.CHOICE:
                choices = [(c, c) for c in q.get_choices_list()]
                self.fields[field_name] = forms.ChoiceField(
                    label=q.text,
                    required=q.required,
                    choices=[("", "Select an option")] + choices,
                    widget=forms.Select(attrs={"class": "form-select"})
                )
            elif q.question_type == SurveyQuestion.QuestionType.RATING:
                self.fields[field_name] = forms.ChoiceField(
                    label=q.text,
                    required=q.required,
                    choices=[(str(i), str(i)) for i in range(1, 6)],
                    widget=forms.RadioSelect(attrs={"class": "form-check-input"}),
                )
            elif q.question_type == SurveyQuestion.QuestionType.INTEGER:
                rules = q.validation_rules or {}
                self.fields[field_name] = forms.IntegerField(
                    label=q.text,
                    required=q.required,
                    min_value=rules.get("min_value"),
                    max_value=rules.get("max_value"),
                    widget=forms.NumberInput(attrs={"class": "form-control"})
                )
            elif q.question_type == SurveyQuestion.QuestionType.DATE:
                rules = q.validation_rules or {}
                attrs = {"type": "date", "class": "form-control"}
                if rules.get("min_date"):
                    attrs["min"] = rules["min_date"]
                if rules.get("max_date"):
                    attrs["max"] = rules["max_date"]
                self.fields[field_name] = forms.DateField(
                    label=q.text,
                    required=q.required,
                    widget=forms.DateInput(attrs=attrs)
                )

    def clean(self):
        cleaned_data = super().clean()
        for q in self.questions:
            field_name = f"question_{q.pk}"
            val = cleaned_data.get(field_name)
            if val is not None and val != "":
                rules = q.validation_rules or {}
                if q.question_type == SurveyQuestion.QuestionType.INTEGER:
                    min_val = rules.get("min_value")
                    max_val = rules.get("max_value")
                    if min_val is not None and val < min_val:
                        self.add_error(field_name, f"Value must be at least {min_val}.")
                    if max_val is not None and val > max_val:
                        self.add_error(field_name, f"Value cannot exceed {max_val}.")
                elif q.question_type == SurveyQuestion.QuestionType.DATE:
                    min_dt_str = rules.get("min_date")
                    max_dt_str = rules.get("max_date")
                    if min_dt_str:
                        min_dt = datetime.date.fromisoformat(min_dt_str)
                        if val < min_dt:
                            self.add_error(field_name, f"Date cannot be before {min_dt_str}.")
                    if max_dt_str:
                        max_dt = datetime.date.fromisoformat(max_dt_str)
                        if val > max_dt:
                            self.add_error(field_name, f"Date cannot be after {max_dt_str}.")
        return cleaned_data

    def save(self, user=None, cid=None, content_type=None, object_id=None, pre_or_post='GENERAL'):
        response_user = None if self.survey.anonymous else user
        response_cid = None if self.survey.anonymous else cid
        
        response = SurveyResponse.objects.create(
            survey=self.survey,
            user=response_user,
            cid=response_cid,
            content_type=content_type,
            object_id=object_id,
            pre_or_post=pre_or_post
        )
        
        for q in self.questions:
            field_name = f"question_{q.pk}"
            val = self.cleaned_data.get(field_name)
            if val is not None and val != "":
                ans = SurveyAnswer(response=response, question=q)
                if q.question_type == SurveyQuestion.QuestionType.TEXT:
                    ans.text_answer = val
                elif q.question_type == SurveyQuestion.QuestionType.CHOICE:
                    ans.choice_answer = val
                elif q.question_type == SurveyQuestion.QuestionType.RATING:
                    ans.rating_answer = int(val)
                elif q.question_type == SurveyQuestion.QuestionType.INTEGER:
                    ans.integer_answer = int(val)
                elif q.question_type == SurveyQuestion.QuestionType.DATE:
                    ans.date_answer = val
                ans.save()
        return response
