# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import datetime

from odoo import Command
from odoo.addons.survey.tests import common
from odoo.tests.common import tagged, HttpCase
from odoo.tools import mute_logger


@tagged('at_install', '-post_install')  # LEGACY at_install
class TestSurveyController(common.TestSurveyCommon, HttpCase):

    def test_submit_route_scoring_after_page(self):
        """ Check that the submit route for a scoring after page survey is returning the
        accurate correct answers depending on the survey layout and the active page questions.
        The correct answers of the inactive conditional questions shouldn't be returned.
        """
        survey = self.env['survey.survey'].create({
            'title': 'How much do you know about words?',
            'scoring_type': 'scoring_with_answers_after_page',
        })
        (
            a_q1_partial, a_q1_correct, a_q1_incorrect,
            a_q2_incorrect, a_q2_correct,
            a_q3_correct, a_q3_incorrect
        ) = self.env['survey.question.answer'].create([
            {'value': 'A thing full of letters.', 'answer_score': 1.0},
            {'value': 'A unit of language, [...], carrying a meaning.', 'answer_score': 4.0, 'is_correct': True},
            {'value': 'A thing related to space', 'answer_score': -4.0},
            {'value': 'Yes', 'answer_score': -0.5},
            {'value': 'No', 'answer_score': 0.5, 'is_correct': True},
            {'value': 'Yes', 'answer_score': 0.5, 'is_correct': True},
            {'value': 'No', 'answer_score': 0.2},
        ])
        q1, q2, q3 = self.env['survey.question'].create([{
            'survey_id': survey.id,
            'title': 'What is a word?',
            'sequence': 2,
            'question_type': 'simple_choice',
            'suggested_answer_ids': [Command.set((a_q1_partial | a_q1_correct | a_q1_incorrect).ids)],
            'constr_mandatory': False,
        }, {
            'survey_id': survey.id,
            'title': 'Are you sure?',
            'sequence': 3,
            'question_type': 'simple_choice',
            'suggested_answer_ids': [Command.set((a_q2_incorrect | a_q2_correct).ids)],
            'triggering_answer_ids': [Command.set((a_q1_partial | a_q1_incorrect).ids)],
            'constr_mandatory': False,
        }, {
            'survey_id': survey.id,
            'title': 'Are you sure?',
            'sequence': 5,
            'question_type': 'simple_choice',
            'suggested_answer_ids': [Command.set((a_q3_correct | a_q3_incorrect).ids)],
            'triggering_answer_ids': [Command.set([a_q1_correct.id])],
            'constr_mandatory': False,
        }])
        pages = [
            {'is_page': True, 'question_type': False, 'sequence': 1, 'title': 'Page 0', 'survey_id': survey.id},
            {'is_page': True, 'question_type': False, 'sequence': 4, 'title': 'Page 1', 'survey_id': survey.id},
        ]

        q1_correct_answer = {str(q1.id): [a_q1_correct.id]}
        cases = [
            ('page_per_question', [], q1_correct_answer),
            ('page_per_question', a_q1_correct, q1_correct_answer),
            ('page_per_question', a_q1_incorrect, q1_correct_answer),
            ('one_page', [], q1_correct_answer), # skipping gives answers for active questions (q2 and q3 conditional questions are inactive)
            ('one_page', a_q1_correct, {**q1_correct_answer, str(q3.id): [a_q3_correct.id]}),
            ('one_page', a_q1_partial, {**q1_correct_answer, str(q2.id): [a_q2_correct.id]}),
            # page0 contains q1 and q2, page1 contains q3
            ('page_per_section', [], q1_correct_answer),
            ('page_per_section', a_q1_correct, q1_correct_answer), # no correct answers for q3 because q3 is not on the same page as q1
            ('page_per_section', a_q1_partial, {**q1_correct_answer, str(q2.id): [a_q2_correct.id]}),
        ]

        for case_index, (layout, answer_q1, expected_correct_answers) in enumerate(cases):
            with self.subTest(case_index=case_index, layout=layout):
                survey.questions_layout = layout
                if layout == 'page_per_section':
                    page0, _ = self.env['survey.question'].create(pages)

                cookie_key = f'survey_{survey.access_token}'
                # clear the cookie to start a new survey
                self.opener.cookies.pop(cookie_key, None)

                response = self._access_start(survey)
                self.assertTrue(response.history, "Survey start should redirect")
                cookie_token = response.history[0].cookies.get(cookie_key)
                user_input = self.env['survey.user_input'].search([('access_token', '=', cookie_token)])
                answer_token = user_input.access_token
                self.assertTrue(cookie_token)
                self.assertTrue(user_input)

                r = self._access_page(survey, answer_token)
                self.assertResponse(r, 200)
                csrf_token = self._find_csrf_token(response.text)

                r = self._access_begin(survey, answer_token)
                self.assertResponse(r, 200)

                post_data = {'csrf_token': csrf_token, 'token': answer_token}
                post_data[q1.id] = answer_q1.id if answer_q1 else answer_q1
                if layout == 'page_per_question':
                    post_data['question_id'] = q1.id
                elif layout == 'page_per_section':
                    post_data['page_id'] = page0.id

                # Submit answers and check the submit route is returning the accurate correct answers
                response = self._access_submit(survey, answer_token, post_data)
                self.assertResponse(response, 200)
                result = response.json()['result']
                self.assertFalse(result[1].get('error'))
                self.assertEqual(result[0], expected_correct_answers)

                user_input.invalidate_recordset() # TDE note: necessary as lots of sudo in controllers messing with cache

    def test_live_session_without_question(self):
        """Test that the live session ('Thank You' page) does not crash when no question is present."""
        survey = self.env['survey.survey'].with_user(self.survey_manager).create({
            'title': 'Live Session Survey',
            'access_mode': 'token',
            'users_login_required': False,
            'session_question_start_time': datetime.datetime(2023, 7, 7, 12, 0, 0),
        })

        self.authenticate(self.survey_manager.login, self.survey_manager.login)

        # Call the url without any question
        session_manage_url = f'/survey/session/manage/{survey.access_token}'
        response = self.url_open(session_manage_url)
        self.assertEqual(response.status_code, 200, "Should be able to open live session manage page")

    def test_live_session_answer_after_result(self):
        """Verify that participants can no longer answer once the results have been shown."""
        survey = self.env['survey.survey'].with_user(self.survey_manager).create({
            'title': 'Live Session Survey',
            'survey_type': 'live_session',
            'question_and_page_ids': [
                Command.create({
                    'title': question, 'question_type': 'multiple_choice',
                    'suggested_answer_ids': [
                        Command.create({'value': '1pt', 'is_correct': True, 'answer_score': 1}),
                        Command.create({'value': '0pt', 'is_correct': False, 'answer_score': 0}),
                    ]
                })
                for question in ('Question1', 'Question2')
            ],
        })
        questions = survey.question_ids

        # Host: Start the live survey
        self.authenticate('survey_manager', 'survey_manager')
        survey.action_start_session()
        self.assertEqual(self._session_next_question(survey).status_code, 200)
        self.assertTrue(survey.session_question_can_answer)
        self.assertEqual(self._session_disable_answers(survey).status_code, 200)
        self.assertFalse(survey.session_question_can_answer)

        # User not member of survey groups cannot go to the next question
        self.authenticate('user_emp', 'user_emp')
        self.assertEqual(survey.session_question_id, questions[0])
        with mute_logger('odoo.http'):
            self._session_next_question(survey)
        self.assertEqual(survey.session_question_id, questions[0], "Only survey user go to the next question")

        # Participant: Attempt to answer question 1 while it is already closed
        self.authenticate(None, None)
        res = self.url_open(survey.get_start_url())
        self.assertEqual(res.status_code, 200)
        self.assertTrue(res.history, "Survey start should redirect")
        answer_token = res.history[0].cookies.get(f'survey_{survey.access_token}')
        csrf_token = self._find_csrf_token(res.text)
        self.assertIn('Question1', res.text)
        post_data = self._format_submission_data(
            survey.question_ids[0], [questions[0].suggested_answer_ids[0].id],
            {'csrf_token': csrf_token, 'token': answer_token})
        res = self._access_submit(survey, answer_token, post_data)
        self.assertEqual(res.status_code, 200)
        self.assertEqual(
            res.json()['result'][1],
            {"error": "validation",
             "fields": {str(survey.question_ids[0].id): "We do not accept submissions for this question anymore."}})

        # Host: Go to Question 2
        self.authenticate('survey_manager', 'survey_manager')
        self.assertEqual(self._session_next_question(survey).status_code, 200)
        self.assertTrue(survey.session_question_can_answer)

        # User not member of survey groups cannot set the result state
        self.authenticate('user_emp', 'user_emp')
        with mute_logger('odoo.http'):
            self._session_disable_answers(survey)
        self.assertTrue(survey.session_question_can_answer, "Only survey user can change session_question_can_answer")

        # Participant: Answer correctly question 2
        self.authenticate(None, None)
        res = self.url_open(survey.get_start_url())
        self.assertEqual(res.status_code, 200)
        self.assertIn('Question2', res.text)
        self.assertTrue(res.history, "Survey start should redirect")
        answer_token = res.history[0].cookies.get(f'survey_{survey.access_token}')
        csrf_token = self._find_csrf_token(res.text)
        post_data = self._format_submission_data(
            survey.question_ids[1], [questions[1].suggested_answer_ids[0].id],
            {'csrf_token': csrf_token, 'token': answer_token})
        res = self._access_submit(survey, answer_token, post_data)
        self.assertEqual(res.status_code, 200)
        self.assertFalse(res.json()['result'][1].get('error'))

        # Host: Check answered questions and scores
        self.authenticate('survey_manager', 'survey_manager')
        self.assertEqual(self._session_next_question(survey).status_code, 200)
        user_inputs = self.env['survey.user_input'].search([
            ('survey_id', '=', survey.id),
            ('create_date', '>=', survey.session_start_time)
        ], order='id')
        self.assertEqual(user_inputs.mapped('user_input_line_ids.question_id.title'), ['Question2'],
                         "Only question 2 has been answered.")
        self.assertEqual(user_inputs.mapped('scoring_total'), [0, 1])
