from django.forms import (
    Form,
    ModelForm,
    ModelMultipleChoiceField,
    ModelChoiceField,
    CheckboxSelectMultiple,
    ChoiceField,
    CharField,
)
from django.forms import inlineformset_factory

from generic.forms import ExamAuthorFormMixin, ExamFormMixin, ExamGroupsFormMixin, ExamMarkerFormMixin

from .models import (
    Question,
    UserAnswer,
    Exam,
    Category
)

from django.contrib.admin.widgets import FilteredSelectMultiple
from django.forms.widgets import RadioSelect, TextInput, Textarea

from tinymce.widgets import TinyMCE
import re

from dal import autocomplete
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, Row, Column, Submit
from generic.widgets import ExamSearchWidget


class UserAnswerForm(ModelForm):
    class Meta:
        model = UserAnswer
        fields = ["answer"]

    def __init__(self, *args, **kwargs):
        super(UserAnswerForm, self).__init__(*args, **kwargs)
        self.fields['answer'].required = False

# This should be made generic?
class ExamForm(ExamFormMixin, ModelForm):
    class Meta(ExamFormMixin.Meta):
        model = Exam

class ExamAuthorForm(ExamAuthorFormMixin):
    class Meta(ExamAuthorFormMixin.Meta):
        model = Exam

class ExamMarkerForm(ExamMarkerFormMixin):
    class Meta(ExamMarkerFormMixin.Meta):
        model = Exam


class ExamGroupsForm(ExamGroupsFormMixin):
    class Meta(ExamGroupsFormMixin.Meta):
        model = Exam

class QuestionForm(ModelForm):

    # exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all())

    class Media:
        # Django also includes a few javascript files necessary
        # for the operation of this form element. You need to
        # include <script src="/admin/jsi18n"></script>
        # in the template.
        css = {
            "all": ["css/widgets.css"],
        }
        # Adding this javascript is crucial
        js = ["jsi18n.js", "tesseract.min.js"]

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop(
            "user"
        )  # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
        if kwargs.get("instance"):
            # We get the 'initial' keyword argument or initialize it
            # as a dict if it didn't exist.
            initial = kwargs.setdefault("initial", {})
            # The widget for a ModelMultipleChoiceField expects
            # a list of primary key for the selected data.
            initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()]

        ModelForm.__init__(self, *args, **kwargs)

        super(QuestionForm, self).__init__(*args, **kwargs)
        # self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100}
        # self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100}
        self.fields["category"] = ModelChoiceField(
            required=True,
            queryset=Category.objects.all(),
            initial=1,
        )


        if self.user.groups.filter(name="sba_checker").exists():
            exam_queryset = Exam.objects.all()
        else:
            exam_queryset = Exam.objects.filter(
                author__id=self.user.id
            ) | Exam.objects.filter(open_access=True)

        self.fields["exams"] = ModelMultipleChoiceField(
            required=False,
            queryset=exam_queryset,
            widget=ExamSearchWidget(exam_model=Exam),
        )

        # Crispy Forms helper and layout
        self.helper = FormHelper()
        self.helper.form_method = "post"
        self.helper.form_enctype = "multipart/form-data"
        self.helper.template_pack = "bootstrap5"
        self.helper.layout = Layout(
            Fieldset(
                "Question",
                "title",
                "stem",
            ),
            Fieldset(
                "Answers",
                # Use responsive columns so they stack on small screens and sit side-by-side on md+
                Row(Column("a_answer", css_class="col-md-6"), Column("a_feedback", css_class="col-md-6")),
                Row(Column("b_answer", css_class="col-md-6"), Column("b_feedback", css_class="col-md-6")),
                Row(Column("c_answer", css_class="col-md-6"), Column("c_feedback", css_class="col-md-6")),
                Row(Column("d_answer", css_class="col-md-6"), Column("d_feedback", css_class="col-md-6")),
                Row(Column("e_answer", css_class="col-md-6"), Column("e_feedback", css_class="col-md-6")),
                "best_answer",
            ),
            Fieldset(
                "Feedback",
                "feedback",
            ),
            Fieldset(
                "Metadata",
                Row(Column("category", css_class="col-md-6"), Column("exams", css_class="col-md-6")),
                Row(Column("open_access", css_class="col-md-4"), Column("frcr_appropriate", css_class="col-md-4")),
            ),
        )
        self.helper.add_input(Submit("submit", "Submit", css_class="btn btn-primary"))

    def save(self, commit=True):
        # Get the unsaved Pizza instance
        instance = ModelForm.save(self, False)
        instance.save()

        old_exams = instance.exams.all()

        new_exams = self.cleaned_data["exams"]

        for exam in old_exams:
            if exam not in new_exams:
                exam.exam_questions.remove(instance)

        for exam in new_exams:
            exam.exam_questions.add(instance)

        self.save_m2m()

        return instance

    def clean(self):
        """Strip a single wrapping <p>...</p> from TinyMCE-provided HTML fields.

        This handles the common TinyMCE behaviour where the editor wraps
        inline content in a root <p>. We only unwrap when the entire value
        is a single <p> element (so multi-paragraph content is preserved).
        """
        cleaned = super(QuestionForm, self).clean()

        def _unwrap_single_p(html: str) -> str:
            if not html or not isinstance(html, str):
                return html
            # Match a single <p ...>...</p> that spans the whole string
            m = re.fullmatch(r"\s*<p\b[^>]*>(.*)</p>\s*", html, flags=re.DOTALL | re.IGNORECASE)
            if m:
                return m.group(1)
            return html

        fields_to_unwrap = [
            "stem",
            "feedback",
            "a_answer",
            "a_feedback",
            "b_answer",
            "b_feedback",
            "c_answer",
            "c_feedback",
            "d_answer",
            "d_feedback",
            "e_answer",
            "e_feedback",
        ]

        for fname in fields_to_unwrap:
            if fname in cleaned:
                cleaned[fname] = _unwrap_single_p(cleaned.get(fname))

        return cleaned

    class Meta:
        model = Question

        fields = [
            "title",
            "stem",
            "feedback",
            "category",
            "a_answer",
            "a_feedback",
            "b_answer",
            "b_feedback",
            "c_answer",
            "c_feedback",
            "d_answer",
            "d_feedback",
            "e_answer",
            "e_feedback",
            "best_answer",
            "finding",
            "structure",
            "condition",
            "presentation",
            "subspecialty",
            "open_access",
            "frcr_appropriate",
        ]

        widgets = {
            # "normal": RadioSelect(
            # choices=[(True, 'Yes'),
            #     (False, 'No')])
            "stem" : TinyMCE(attrs={'cols': 80, 'rows': 30}),
            "feedback" : TinyMCE(attrs={'cols': 80, 'rows': 30}),
            "a_answer" : TinyMCE(attrs={'cols': 80, 'rows': 5}, mce_attrs={'height': 200}),
            "a_feedback" : TinyMCE(attrs={'cols': 80, 'rows': 5}, mce_attrs={'height': 200}),
            "b_answer" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "c_answer" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "d_answer" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "e_answer" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "b_feedback" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "c_feedback" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "d_feedback" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "e_feedback" : TinyMCE(attrs={'cols': 80, 'rows': 4}, mce_attrs={'height': 200}),
            "structure": autocomplete.ModelSelect2Multiple(
                url="atlas:structure-autocomplete"
            ),
            "finding": autocomplete.ModelSelect2Multiple(
                url="atlas:finding-autocomplete"
            ),
            "condition": autocomplete.ModelSelect2Multiple(
                url="atlas:condition-autocomplete"
            ),
            "presentation": autocomplete.ModelSelect2Multiple(
                url="atlas:presentation-autocomplete"
            ),
            "subspecialty": CheckboxSelectMultiple(),
        }

        #widgets = {
        #    "structure": autocomplete.ModelSelect2(url="anatomy:structure-autocomplete")
        #}
