# Standard Library
from datetime import datetime
from io import BytesIO
from types import SimpleNamespace
from uuid import uuid4

# Django
from django.test import SimpleTestCase
from django.utils.translation import override

# Third party
from openpyxl import load_workbook

# Project
from django_easy_quiz.exporters.saved_quiz_export import xlsx_response


class SavedQuizExportTests(SimpleTestCase):
    def _saved_quiz(self, **kwargs):
        defaults = {
            "id": 1,
            "uuid": uuid4(),
            "started_quiz": datetime(2026, 1, 1, 10, 0, 0),
            "quiz_ended": True,
            "quiz_type": "Personality Quiz",
            "weighted_answers_quiz_id": None,
            "interpretation_quiz_id": None,
            "weighted_answers_quiz": None,
            "interpretation_quiz": None,
            "conclusion": {},
            "answers": [],
            "more_infos": [],
        }
        defaults.update(kwargs)
        return SimpleNamespace(**defaults)

    def _quiz(self, quiz_id, name, create_date, show_answers_corrections_text=False):
        return SimpleNamespace(
            id=quiz_id,
            name=name,
            create_date=create_date,
            show_answers_corrections_text=show_answers_corrections_text,
        )

    def _parse_workbook(self, response):
        return load_workbook(BytesIO(response.content))

    def test_xlsx_excludes_not_ended_quizzes(self):
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=3,
            weighted_answers_quiz=self._quiz(3, "WA 3", datetime(2026, 1, 2, 10, 0, 0)),
            conclusion={"points": 7, "description": "<p>Great!</p>"},
            answers=[
                {
                    "question": {"label": "Favorite fruits"},
                    "answers": ["<b>Apple</b>", "Pear"],
                }
            ],
            more_infos=[{"question": "Email", "answer": "john@example.com"}],
        )
        unfinished = self._saved_quiz(
            id=99,
            quiz_ended=False,
            weighted_answers_quiz_id=3,
            weighted_answers_quiz=self._quiz(3, "WA 3", datetime(2026, 1, 2, 10, 0, 0)),
            answers=[{"question": {"label": "Should not exist"}, "answers": ["X"]}],
        )

        with override("fr"):
            response = xlsx_response([saved_quiz, unfinished], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        sheet = workbook["#3 - WA 3"]
        self.assertEqual(sheet.max_row, 2)
        self.assertEqual(sheet["A2"].value, 1)

    def test_xlsx_creates_one_sheet_per_selected_quiz(self):
        wa_old = self._quiz(1, "WA 1", datetime(2026, 1, 1, 10, 0, 0))
        wa_new = self._quiz(2, "WA 2", datetime(2026, 1, 3, 10, 0, 0))
        saved_quiz = self._saved_quiz(
            id=10,
            weighted_answers_quiz_id=1,
            weighted_answers_quiz=wa_old,
            answers=[
                {"question": {"label": "Question 1"}, "answers": ["A"]},
            ],
        )
        saved_quiz_new = self._saved_quiz(
            id=11,
            weighted_answers_quiz_id=2,
            weighted_answers_quiz=wa_new,
            answers=[{"question": {"label": "Question 2"}, "answers": ["B"]}],
        )

        with override("fr"):
            response = xlsx_response([saved_quiz, saved_quiz_new], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)

        self.assertEqual(workbook.sheetnames, ["#2 - WA 2", "#1 - WA 1"])

    def test_xlsx_header_style_and_question_labels(self):
        wa_quiz = self._quiz(
            7,
            "WA 7",
            datetime(2026, 1, 4, 10, 0, 0),
            show_answers_corrections_text=True,
        )
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=7,
            weighted_answers_quiz=wa_quiz,
            quiz_type="WA Seven",
            answers=[{"question": {"label": "Favorite fruits"}, "answers": ["Apple"]}],
        )

        with override("fr"):
            response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        sheet = workbook["#7 - WA 7"]

        header_values = [cell.value for cell in sheet[1]]
        self.assertIn("Question n°1 : Favorite fruits", header_values)
        self.assertIn("Réponse question n°1", header_values)
        self.assertIn("Texte explicatif question n°1", header_values)
        self.assertTrue(all(cell.font.bold for cell in sheet[1]))

        # Width is capped to ~600px equivalent
        first_letter = sheet[1][0].column_letter
        self.assertLessEqual(sheet.column_dimensions[first_letter].width, 85.0)

    def test_xlsx_sheet_title_is_sanitized(self):
        quiz = self._quiz(
            12, "Au travail : quels risques pour", datetime(2026, 1, 4, 10, 0, 0)
        )
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=12,
            weighted_answers_quiz=quiz,
            answers=[{"question": {"label": "Q1"}, "answers": ["A1"]}],
        )

        response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        self.assertEqual(workbook.sheetnames[0], "#12 - Au travail quels risques")

    def test_xlsx_more_info_headers_use_question_text_not_slug(self):
        wa_quiz = self._quiz(5, "Main quiz", datetime(2026, 1, 5, 10, 0, 0))
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=5,
            weighted_answers_quiz=wa_quiz,
            answers=[{"question": {"label": "Q1"}, "answers": ["A"]}],
            more_infos=[
                {
                    "question": "Dans quel département vivez-vous ?",
                    "answer": "26",
                }
            ],
        )
        with override("fr"):
            response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        sheet = workbook["#5 - Main quiz"]
        header_values = [cell.value for cell in sheet[1]]
        self.assertIn("Dans quel département vivez-vous ?", header_values)
        self.assertNotIn("dans-quel-departement-vivez-vous", header_values)

    def test_xlsx_exports_answers_explanatory_text(self):
        wa_quiz = self._quiz(
            13,
            "WA 13",
            datetime(2026, 1, 4, 10, 0, 0),
            show_answers_corrections_text=True,
        )
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=13,
            weighted_answers_quiz=wa_quiz,
            answers=[
                {
                    "question": {"label": "Question 1"},
                    "answers": ["<b>1</b>", "2"],
                    "question_explanation_text": "<p>Info 1</p>",
                }
            ],
        )

        with override("fr"):
            response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        sheet = workbook["#13 - WA 13"]

        header_values = [cell.value for cell in sheet[1]]
        answer_info_index = header_values.index("Texte explicatif question n°1") + 1
        self.assertEqual(sheet.cell(row=2, column=answer_info_index).value, "Info 1")

    def test_xlsx_interpretation_quiz_uses_answer_field(self):
        interpretation_quiz = self._quiz(
            21, "Interpretation 21", datetime(2026, 1, 6, 10, 0, 0)
        )
        saved_quiz = self._saved_quiz(
            interpretation_quiz_id=21,
            interpretation_quiz=interpretation_quiz,
            answers=[
                {
                    "question": {"label": "Interpretation question"},
                    "answer": "■ - Option A",
                }
            ],
        )

        with override("en"):
            response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        sheet = workbook["#21 - Interpretation 21"]

        headers = [cell.value for cell in sheet[1]]
        answer_index = headers.index("Answer question #1") + 1
        self.assertEqual(sheet.cell(row=2, column=answer_index).value, "■ - Option A")

    def test_xlsx_fallback_sheet_when_no_answers(self):
        wa_quiz = self._quiz(30, "WA Empty", datetime(2026, 1, 6, 10, 0, 0))
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=30,
            weighted_answers_quiz=wa_quiz,
            answers=[],
        )

        with override("en"):
            response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)

        self.assertEqual(workbook.sheetnames, ["saved_quizzes"])
        sheet = workbook["saved_quizzes"]
        self.assertEqual(sheet.max_row, 1)
        self.assertEqual(sheet["A1"].value, "ID")

    def test_xlsx_strips_html_and_images_in_answers(self):
        wa_quiz = self._quiz(
            31,
            "WA HTML",
            datetime(2026, 1, 6, 10, 0, 0),
            show_answers_corrections_text=True,
        )
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=31,
            weighted_answers_quiz=wa_quiz,
            answers=[
                {
                    "question": {"label": "<b>Question</b>"},
                    "answers": ['<img src="/media/a.png" alt="pic">Answer <b>A</b>'],
                    "question_explanation_text": "<p>Info <img src='/media/i.png' /> detail</p>",
                }
            ],
        )

        with override("en"):
            response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        sheet = workbook["#31 - WA HTML"]
        headers = [cell.value for cell in sheet[1]]
        answer_index = headers.index("Answer question #1") + 1
        answer_info_index = headers.index("Explanatory text question #1") + 1

        self.assertEqual(sheet.cell(row=2, column=answer_index).value, "Answer A")
        self.assertEqual(
            sheet.cell(row=2, column=answer_info_index).value, "Info  detail"
        )

    def test_xlsx_hides_explanatory_columns_when_quiz_option_disabled(self):
        wa_quiz = self._quiz(41, "WA 41", datetime(2026, 1, 6, 10, 0, 0))
        saved_quiz = self._saved_quiz(
            weighted_answers_quiz_id=41,
            weighted_answers_quiz=wa_quiz,
            answers=[
                {
                    "question": {"label": "Question 1"},
                    "answers": ["A"],
                    "question_explanation_text": "<p>Info 1</p>",
                }
            ],
        )

        with override("en"):
            response = xlsx_response([saved_quiz], "saved_quizzes.xlsx")
        workbook = self._parse_workbook(response)
        sheet = workbook["#41 - WA 41"]
        headers = [cell.value for cell in sheet[1]]
        self.assertNotIn("Explanatory text question #1", headers)
