# Standard Library
from uuid import uuid4

# Django
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _

# Third party
from ckeditor_uploader.fields import RichTextUploadingField

# Quiz


class Quiz(models.Model):
    name = models.CharField(_("Quiz name"), max_length=1024)
    questions_random = models.BooleanField(
        default=False,
        verbose_name=_("Random questions"),
        help_text=_("Questions will be shown on random order."),
    )
    answers_random = models.BooleanField(
        default=False,
        verbose_name=_("Random answers"),
        help_text=_("Answers will be shown on random order."),
    )
    create_date = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_("Creation date"),
    )
    description = RichTextUploadingField(verbose_name=_("Description"))
    more_info_quiz = models.ForeignKey(
        "MoreInfoQuiz",
        default=None,
        blank=True,
        null=True,
        on_delete=models.PROTECT,
        verbose_name=_("More info quiz"),
        help_text=_("Will display this 'more info quiz' at the end of the main quiz."),
    )

    def __str__(self):
        return f"{self.name}"

    class Meta:
        abstract = True


class WeightedAnswersQuiz(Quiz):
    show_score_summary = models.BooleanField(
        default=True, verbose_name=_("Show score in summary")
    )
    show_answers_corrections_text = models.BooleanField(
        default=False, verbose_name=_("Show answers explanatory text in summary")
    )

    class Meta:
        verbose_name = _("Weighted Answers Quiz")
        verbose_name_plural = _("Weighted Answers Quizzes")

    def get_absolute_url(self):
        return reverse("weighted_answers_quiz", kwargs={"pk": self.pk})


class InterpretationQuiz(Quiz):
    class Meta:
        verbose_name = _("Interpretation Quiz")
        verbose_name_plural = _("Interpretation Quizzes")

    def get_absolute_url(self):
        return reverse("interpretation_quiz", kwargs={"pk": self.pk})


# Questions


class Question(models.Model):
    label = models.CharField(_("Question"), max_length=1024)

    class Meta:
        abstract = True


class WeightedAnswersQuizQuestion(Question):
    quiz = models.ForeignKey(
        WeightedAnswersQuiz,
        on_delete=models.CASCADE,
        verbose_name=_("Weighted answers quiz"),
    )
    label = models.CharField(verbose_name=_("Question"), max_length=1024)
    order = models.PositiveIntegerField(default=0, verbose_name=_("Display order"))
    multiple_answers = models.BooleanField(
        default=False, verbose_name=_("More than one answer possible")
    )
    question_explanation_text = RichTextUploadingField(
        verbose_name=_("Explanation text for question"), null=True, blank=True
    )

    def __str__(self):
        return f"{self.label}"

    def toJson(self):
        return {
            "label": self.label,
            "multiple_answers": self.multiple_answers,
            "question_explanation_text": self.question_explanation_text,
        }

    class Meta:
        verbose_name = _("Weighted Answers Quiz Question")
        verbose_name_plural = _("Weighted Answers Quiz Questions")
        ordering = ("order", "id")


class InterpretationQuizQuestion(Question):
    quiz = models.ForeignKey(
        InterpretationQuiz,
        on_delete=models.CASCADE,
        verbose_name=_("Interpretation quiz"),
    )
    label = models.CharField(verbose_name=_("Question"), max_length=1024)
    order = models.PositiveIntegerField(default=0, verbose_name=_("Display order"))

    def __str__(self):
        return f"{self.label}"

    def toJson(self):
        answers_by_symbol = {
            answer.symbol: answer.label
            for answer in self.answers.all().order_by("order", "id")
        }
        return {
            "label": self.label,
            "answer_1": f"■ - {answers_by_symbol.get('■', '')}",
            "answer_2": f"▲ - {answers_by_symbol.get('▲', '')}",
            "answer_3": f"◆ - {answers_by_symbol.get('◆', '')}",
            "answer_4": f"● - {answers_by_symbol.get('●', '')}",
        }

    class Meta:
        verbose_name = _("Interpretation Quiz Question")
        verbose_name_plural = _("Interpretation Quiz Questions")
        ordering = ("order", "id")


# Answers


class Answer(models.Model):
    answer = RichTextUploadingField(verbose_name=_("Answer"))

    def __str__(self):
        return gettext("Answer #%s") % self.id

    class Meta:
        abstract = True


INTERPRETATION_QUESTION_CHOICES = (
    ("■", "■"),
    ("▲", "▲"),
    ("◆", "◆"),
    ("●", "●"),
)


class WeightedAnswersQuizAnswer(models.Model):
    question = models.ForeignKey(
        WeightedAnswersQuizQuestion,
        on_delete=models.CASCADE,
        related_name="answers",
        verbose_name=_("Question"),
    )
    label = RichTextUploadingField(verbose_name=_("Answer"))
    points = models.IntegerField(verbose_name=_("Points for answer"))
    order = models.PositiveIntegerField(default=0, verbose_name=_("Display order"))

    def __str__(self):
        return ""

    class Meta:
        verbose_name = _("Weighted Answers Quiz Answer")
        verbose_name_plural = _("Weighted Answers Quiz Answers")
        ordering = ("order", "id")


class InterpretationQuizAnswer(models.Model):
    question = models.ForeignKey(
        InterpretationQuizQuestion,
        on_delete=models.CASCADE,
        related_name="answers",
        verbose_name=_("Question"),
    )
    symbol = models.CharField(
        max_length=1,
        choices=INTERPRETATION_QUESTION_CHOICES,
        verbose_name=_("Answer symbol"),
    )
    label = RichTextUploadingField(verbose_name=_("Answer"))
    order = models.PositiveIntegerField(default=0, verbose_name=_("Display order"))

    class Meta:
        verbose_name = _("Interpretation Quiz Answer")
        verbose_name_plural = _("Interpretation Quiz Answers")
        ordering = ("order", "id")


# Conclusions/results


class QuizConclusion(models.Model):
    description = RichTextUploadingField(verbose_name=_("Description"))

    class Meta:
        abstract = True


class WeightedAnswersQuizConclusion(QuizConclusion):
    quiz = models.ForeignKey(
        WeightedAnswersQuiz,
        on_delete=models.CASCADE,
        verbose_name=_("Weighted answers quiz"),
    )
    min_points = models.IntegerField(verbose_name=_("Min amount of points (included)"))
    max_points = models.IntegerField(verbose_name=_("Max amount of points (included)"))

    def __str__(self):
        return gettext("Weighted Answers Quiz Conclusion") + " #" + str(self.id)

    class Meta:
        verbose_name = _("Weighted Answers Quiz Conclusion")
        verbose_name_plural = _("Weighted Answers Quiz Conclusions")


class InterpretationQuizConclusion(models.Model):
    quiz = models.ForeignKey(
        InterpretationQuiz,
        on_delete=models.CASCADE,
        related_name="conclusions",
        verbose_name=_("Interpretation quiz"),
    )
    symbol = models.CharField(
        max_length=1,
        choices=INTERPRETATION_QUESTION_CHOICES,
        verbose_name=_("Conclusion symbol"),
    )
    description = RichTextUploadingField(verbose_name=_("Description"))

    class Meta:
        verbose_name = _("Interpretation Quiz Conclusion")
        verbose_name_plural = _("Interpretation Quiz Conclusions")
        constraints = [
            models.UniqueConstraint(
                fields=("quiz", "symbol"),
                name="uniq_interpretation_conclusion_symbol_per_quiz",
            )
        ]


# Djangocms Plugins


class BasePlugin(models.Model):
    LEVEL_1 = "h1"
    LEVEL_2 = "h2"
    LEVEL_3 = "h3"
    LEVEL_4 = "h4"
    LEVEL_5 = "h5"
    LEVEL_6 = "h6"
    TITLE_LEVEL = [
        (LEVEL_1, _("Title level 1 (<h1>)")),
        (LEVEL_2, _("Title level 2 (<h2>)")),
        (LEVEL_3, _("Title level 3 (<h3>)")),
        (LEVEL_4, _("Title level 4 (<h4>)")),
        (LEVEL_5, _("Title level 5 (<h5>)")),
        (LEVEL_6, _("Title level 6 (<h6>)")),
    ]

    title_level = models.CharField(
        verbose_name=_("Title level"),
        choices=TITLE_LEVEL,
        max_length=4,
        help_text=_("Heading level used to render the quiz title."),
    )
    short_description = models.CharField(
        _("Short description"),
        max_length=1024,
        null=True,
        blank=True,
    )
    button_text = models.CharField(
        _("Button text"),
        max_length=1024,
        null=True,
        blank=True,
    )

    class Meta:
        abstract = True


class SavedQuiz(models.Model):
    uuid = models.UUIDField(default=uuid4, editable=False, verbose_name=_("UUID"))
    quiz_type = models.CharField(max_length=255, verbose_name=_("Quiz type"))
    started_quiz = models.DateTimeField(
        auto_now_add=True, verbose_name=_("Started quiz")
    )
    quiz_ended = models.BooleanField(default=False, verbose_name=_("Quiz ended"))
    answers = models.JSONField(default=dict, verbose_name=_("Answers"))
    weighted_answers_quiz = models.ForeignKey(
        WeightedAnswersQuiz,
        null=True,
        blank=True,
        on_delete=models.PROTECT,
        verbose_name=_("Weighted answers quiz"),
    )
    interpretation_quiz = models.ForeignKey(
        InterpretationQuiz,
        null=True,
        blank=True,
        on_delete=models.PROTECT,
        verbose_name=_("Interpretation quiz"),
    )
    interpretation_max_symbol = models.CharField(
        max_length=32,
        null=True,
        blank=True,
        verbose_name=_("Interpretation max symbol"),
    )
    conclusion = models.JSONField(default=dict, verbose_name=_("Conclusion"))
    more_infos = models.JSONField(default=dict, verbose_name=_("More infos"))

    class Meta:
        verbose_name = _("Saved Quiz")
        verbose_name_plural = _("Saved Quizzes")


class MoreInfoQuiz(models.Model):
    name = models.CharField(
        max_length=255,
        help_text=_("Will be displayed below the results."),
        verbose_name=_("Name"),
    )

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = _("More-Info Quiz")
        verbose_name_plural = _("More-Info Quizzes")


class MoreInfoQuestion(models.Model):
    label = models.CharField(max_length=255, verbose_name=_("Label"))
    quiz = models.ForeignKey(
        MoreInfoQuiz, on_delete=models.PROTECT, verbose_name=_("Quiz")
    )
    is_required = models.BooleanField(
        default=False,
        help_text=_("Is this question required?"),
        verbose_name=_("Is required"),
    )
    answer_is_txt = models.BooleanField(
        default=False,
        help_text=_(
            "Check this parameter to allow plain text answers instead of pre-defined answers."
        ),
        verbose_name=_("Answer is text"),
    )
    answer_is_list = models.BooleanField(
        default=False,
        help_text=_(
            "Check this parameter to display a big list of answers using a select input and not radio buttons."
        ),
        verbose_name=_("Answer is list"),
    )

    def __str__(self):
        return self.label

    class Meta:
        verbose_name = _("More-Info Question")
        verbose_name_plural = _("More-Info Questions")


class MoreInfoAnswer(models.Model):
    question = models.ForeignKey(
        MoreInfoQuestion, on_delete=models.PROTECT, verbose_name=_("Question")
    )
    answer = models.CharField(max_length=512, verbose_name=_("Answer"))

    def __str__(self):
        return self.answer

    class Meta:
        verbose_name = _("More-Info Answer")
        verbose_name_plural = _("More-Info Answers")


try:
    # Third party
    from cms.models.pluginmodel import CMSPlugin

    class WeightedAnswersPlugin(BasePlugin, CMSPlugin):
        quiz = models.ForeignKey(
            WeightedAnswersQuiz,
            on_delete=models.SET_NULL,
            null=True,
            verbose_name=_("Weighted answers quiz"),
        )

        class Meta:
            verbose_name = _("Weighted Answers Quiz")
            verbose_name_plural = _("Weighted Answers Quizzes")

    class InterpretationPlugin(BasePlugin, CMSPlugin):
        quiz = models.ForeignKey(
            InterpretationQuiz,
            on_delete=models.SET_NULL,
            null=True,
            verbose_name=_("Interpretation quiz"),
        )

        class Meta:
            verbose_name = _("Interpretation Quiz")
            verbose_name_plural = _("Interpretation Quizzes")

except ImportError:
    ...
