import uuid

from django.db import models
from django.utils import timezone

from authenticate.models import User
from institute.models import Institute, InstituteStudent
from question.models import Question
from wikiazma.storage_helper import public_storage

QUIZ_SHEET_STATE_NOT_ATTENDED = 'not_attended'
QUIZ_SHEET_STATE_IN_PROGRESS = 'in_progress'
QUIZ_SHEET_STATE_FINISHED = 'finished'
QUIZ_SHEET_STATE_SCORES_PUBLISHED = 'scores_published'

QUIZ_SHEETES = [(QUIZ_SHEET_STATE_NOT_ATTENDED, "Not Attended"), (QUIZ_SHEET_STATE_IN_PROGRESS, "In Progress"),
                (QUIZ_SHEET_STATE_FINISHED, "Finished"), (QUIZ_SHEET_STATE_SCORES_PUBLISHED, "Scores Published"), ]

QUIZ_TYPE_DEFAULT = 'default'
QUIZ_TYPE_SURVEY = 'survey'

QUIZ_TYPES = [(QUIZ_TYPE_DEFAULT, "Default"), (QUIZ_TYPE_SURVEY, "Survey")]


class QuizAbstract(models.Model):
    class Meta:
        abstract = True

    name = models.CharField(max_length=500, db_index=True)
    institute = models.ForeignKey(
        Institute, on_delete=models.PROTECT, db_index=True)
    _blueprint = models.JSONField(default=dict)

    single_question_at_a_time = models.BooleanField(
        db_index=True, default=True)
    reanswerable = models.BooleanField(db_index=True, default=True)

    shuffle_questions = models.BooleanField(db_index=True, default=True)
    shuffle_choices = models.BooleanField(db_index=True, default=True)

    apply_negative_scores = models.BooleanField(db_index=True)

    poster = models.ImageField(
        upload_to='quiz/posters', null=True, blank=True, storage=public_storage)
    poster_thumbnail = models.ImageField(
        upload_to='quiz/posters_thumbnails', null=True, blank=True, storage=public_storage)
    theme = models.CharField(max_length=20)
    description = models.TextField(max_length=3000, null=True, blank=True)

    quiz_type = models.CharField(
        choices=QUIZ_TYPES, default=QUIZ_TYPE_DEFAULT, max_length=20)
    custom_report_card = models.FileField(
        upload_to='quiz/report_cards', null=True, blank=True, storage=public_storage)

    duration = models.DurationField(db_index=True, null=True, blank=True)
    questions_count = models.IntegerField(db_index=True)

    finish_message = models.TextField(max_length=1000, null=True, blank=True)
    archived = models.BooleanField(default=False, db_index=True)

    created_at = models.DateTimeField(auto_now_add=True, db_index=True)
    modified_at = models.DateTimeField(auto_now=True, db_index=True)

    @property
    def id(self):
        return self.pk

    def __str__(self):
        return self.name


class QuizTemplate(QuizAbstract):
    price = models.PositiveIntegerField(default=0)

    use_count = models.IntegerField(db_index=True, default=0)

    public = models.BooleanField(db_index=True, default=False)
    featured = models.BooleanField(default=False, db_index=True)
    priority = models.IntegerField(db_index=True, default=0)


class Quiz(QuizAbstract):
    price = models.PositiveIntegerField(default=0)
    wage_free = models.BooleanField(default=False)
    vax_free = models.BooleanField(default=False)

    public = models.BooleanField(default=False, db_index=True)
    featured = models.BooleanField(default=False, db_index=True)
    priority = models.IntegerField(db_index=True, default=0)

    creator = models.ForeignKey(
        User, on_delete=models.SET_NULL, null=True, related_name='created_quiz_set')
    last_editor = models.ForeignKey(
        User, on_delete=models.SET_NULL, null=True, blank=True, related_name='edited_quiz_set')

    start = models.DateTimeField(db_index=True, null=True, blank=True)
    end = models.DateTimeField(db_index=True, null=True, blank=True)

    report_card = models.JSONField(default=dict, blank=True)

    def can_be_entered_state(self):
        # if request.middleware_quiz.paused:
        #     return MyResponse(request, {'status': 'quiz_paused', 'message': 'The quiz has paused'},
        #                       status=status.HTTP_400_BAD_REQUEST)

        # datetime.now() is not timezone aware
        # timezone.now() is timezone aware
        # quiz_sheet.start_date is timezone aware
        # we can't compare offset-naive and offset-aware datetimes
        if self.start and self.start > timezone.now():
            return 'quiz_not_started', 'Quiz is not started.'

        if self.end and self.end < timezone.now():
            return QUIZ_ENDED_STATE, 'Quiz has ended.'

        return None, None


QUIZ_ENDED_STATE = 'quiz_ended'


class QuizSheet(models.Model):
    referer_id = models.UUIDField(
        primary_key=True, unique=True, db_index=True, default=uuid.uuid4, editable=False)
    quiz = models.ForeignKey(Quiz, on_delete=models.PROTECT, db_index=True)
    entrance_token = models.CharField(
        max_length=60, db_index=True, unique=True, null=True, blank=True)
    _questions_sheet = models.JSONField()
    _solutions_sheet = models.JSONField(null=True, blank=True)
    _quizee_inputs_sheet = models.JSONField(
        null=True, blank=True, default=list)

    user = models.ForeignKey(
        User, on_delete=models.SET_NULL, db_index=True, null=True, blank=True)

    institute_student = models.ForeignKey(
        InstituteStudent, on_delete=models.SET_NULL, db_index=True, null=True, blank=True)

    entrance_date = models.DateTimeField(db_index=True, null=True)
    finished_at = models.DateTimeField(db_index=True, null=True)
    allowed_start_at = models.DateTimeField(
        db_index=True, null=True, blank=True)
    allowed_finish_at = models.DateTimeField(
        db_index=True, null=True, blank=True)
    duration = models.DurationField(db_index=True, null=True, blank=True)

    last_quizee_input_index = models.PositiveIntegerField(null=True)
    final_score = models.CharField(max_length=10, null=True, blank=True)
    state = models.CharField(max_length=20, db_index=True,
                             choices=QUIZ_SHEETES, default=QUIZ_SHEET_STATE_NOT_ATTENDED)
    stats = models.JSONField(null=True, blank=True, default=list)

    report_card = models.JSONField(null=True, blank=True)

    created_at = models.DateTimeField(auto_now_add=True, db_index=True)
    modified_at = models.DateTimeField(auto_now=True, db_index=True)

    def get_question_by_index(self, index):
        for question in self._questions_sheet['questions']:
            if index == question['index']:
                return question

        return None

    def get_solution_by_index(self, index):
        for solution in self._solutions_sheet['solutions']:
            if index == solution['index']:
                return solution

        return None

    def can_be_continued_state(self):
        if self.state == QUIZ_SHEET_STATE_FINISHED:
            return 'quiz_closed', 'Quiz has been closed.'

        if self.state == QUIZ_SHEET_STATE_SCORES_PUBLISHED:
            return 'scores_published', 'Quiz has been closed.'

        # datetime.now() is not timezone aware
        # timezone.now() is timezone aware
        # quiz_sheet.start_date is timezone aware
        # we can't compare offset-naive and offset-aware datetimes
        if self.allowed_start_at and self.allowed_start_at > timezone.now():
            return 'quiz_not_started', 'Quiz is not started.'

        if self.allowed_finish_at:
            if self.duration and self.entrance_date:
                if self.allowed_finish_at < self.entrance_date + self.duration:
                    # 3616372662
                    final_end_date = self.allowed_finish_at
                else:
                    # 1736756273
                    final_end_date = self.entrance_date + self.duration
            else:
                final_end_date = self.allowed_finish_at  # 6735673855
        else:
            if self.duration and self.entrance_date:
                # 417536827
                final_end_date = self.entrance_date + self.duration
            else:
                final_end_date = None

        if final_end_date and final_end_date < timezone.now():
            return QUIZ_ENDED_STATE, 'Quiz has ended.'

        return None, None


class QuestionScore(models.Model):
    id = models.UUIDField(primary_key=True, unique=True,
                          db_index=True, default=uuid.uuid4, editable=False)
    corrector = models.ForeignKey(
        User, on_delete=models.SET_NULL, db_index=True, null=True)
    quiz_sheet = models.ForeignKey(
        QuizSheet, on_delete=models.PROTECT, db_index=True)
    question = models.ForeignKey(
        Question, on_delete=models.SET_NULL, db_index=True, null=True)
    question_index = models.IntegerField()
    blank = models.BooleanField(db_index=True)
    score = models.FloatField(null=True, blank=True)
    correct_choices = models.IntegerField(null=True, blank=True)
    wrong_choices = models.IntegerField(null=True, blank=True)
    blank_choices = models.IntegerField(null=True, blank=True)
    comment_for_student = models.TextField(
        max_length=3000, null=True, blank=True)
    comment_for_other_correctors = models.TextField(
        max_length=3000, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)
    modified_at = models.DateTimeField(auto_now=True,
                                       db_index=True)  # TODO: psycopg2.errors.DuplicateTable  # class Meta:  #     index_together = [['exam_page', 'group_index', 'question_index']]  #     unique_together = [['exam_page', 'group_index', 'question_index']]
