"""Test the management commands of the ``assessments`` app."""

from contextlib import contextmanager
from unittest.mock import patch

from django.core.management import call_command
from django.test import override_settings

from mtp.apps.assessments.models import CompetencyTree
from mtp.apps.assessments.tests.test_cases import MTPComplexAssessmentTestCase
from mtp.apps.trainings.models import TrainingSession


class BaseComputeAssessmentScoresTestCase(MTPComplexAssessmentTestCase):
    """Test class to tests the ``computeassessmentscores`` command."""

    def setUp(self):
        """Prepare data to tests the ``computeassessmentscores`` command."""

        super().setUp()

        # We keep only ``self.trainee`` in session users.
        for user in self.training_session.users.all():
            if user.id != self.trainee.id:
                self.training_session.users.remove(user)

        # Arbitrary scores for ``self.trainee``.
        self._record_global_score(37)
        self._record_competency_scores([43, 25])
        self._record_dimension_scores([56, 40, 36, 30, 26, 25])
        self._compute_certification_status()

    @contextmanager
    def assertSessionRecomputed(self):
        """Assert that the session is recomputed.

        We check if the `compute_assessment_scores` is called.

        """

        with patch.object(TrainingSession, 'compute_assessment_scores') as mock_method:
            yield

        try:
            self.assertTrue(mock_method.called)
        except AssertionError:
            self.fail("Session is not recomputed.")


class ComputeAssessmentScoresTestCase(BaseComputeAssessmentScoresTestCase):
    """Test class to tests the ``computeassessmentscores`` command."""

    def test_command_should_works(self):
        """Test the ``computeassessmentscores`` command should works."""

        users = self.training_session.users
        self.assertEqual(users.count(), 1)
        self.assertEqual(users.get(), self.trainee)

        # The competency tree score is already computed in ``setUp`` method.
        # We don't want force recomputed it because we don't have ``AssessmentPartScore``
        with patch.object(CompetencyTree, 'compute_scores', return_value=None):

            with self.assertSessionRecomputed():
                call_command("computeassessmentscores")

            with override_settings(INSTANCE_IS_MASTER=True):
                self.training_session.close()

            with self.assertRaises(self.failureException):
                with self.assertSessionRecomputed():
                    call_command("computeassessmentscores")

            with self.assertSessionRecomputed():
                call_command("computeassessmentscores", "--force")
