"""This module contains the tests for the Nissan-specific ``import_export`` app."""

import csv
import filecmp
import os
import tempfile

from constance import config

from mtp.apps.accounts.constants import (
    GROUPTYPE_BUSINESS_LEVEL,
    GROUPTYPE_BUSINESS_ZONE,
    GROUPTYPE_JOB_NAME,
    GROUPTYPE_JOB_TYPE,
)
from mtp.apps.accounts.factories import GroupTypeFactory
from mtp.apps.accounts.models import MTPUser
from mtp.apps.assessments.models import LessonReference
from mtp.apps.common.tests.test_cases import MTPTestCase

from .saba import CourseImporter, SabaImporter, UserImporter


class SabaImporterTestCase(MTPTestCase):
    """Test the ``SabaImporter`` class"""

    @classmethod
    def setUpClass(cls):
        """Prepare a file with utf-8 data and an importer"""

        super().setUpClass()

        __, cls.input_file_path = tempfile.mkstemp()
        with open(cls.input_file_path, 'w', encoding='utf-8') as input_file:
            input_file.write('Français')

        cls.importer = SabaImporter()

    @classmethod
    def tearDownClass(cls):
        """Remove our test files"""

        os.remove(cls.input_file_path)
        os.remove(cls.importer.import_file_path)

        super().tearDownClass()

    def test_handle_upload(self):
        """Test the handle upload method with utf-8 data"""

        class MockedRequest:
            """A mocked request for our test"""

            FILES = {}

        import_file = open(self.input_file_path, 'rb')

        request = MockedRequest()
        request.FILES['test_import_file'] = import_file

        self.importer.handle_upload(request, 'test_import_file')

        self.assertTrue(filecmp.cmp(self.importer.import_file_path, self.input_file_path))


class BaseImporterTestCase(MTPTestCase):
    """Setup base test data for our importers tests"""

    @classmethod
    def tearDownClass(cls):
        """Remove our test temp file when leaving

        This should be done by the import mecanism, but let's make sure it
        is deleted in case the test crashes before deleting the file.
        """

        super().tearDownClass()

        try:
            os.remove(cls.import_file_path)
        except FileNotFoundError:
            pass

    @classmethod
    def setup_csv_test_file(cls, csv_rows, importer_class):
        """Helper function to setup the test CSV file and feed it to the import

        Meant to be called by subclasses at the end of ``setUpClass``.

        Parameters
        ----------
        csv_rows: list
            List of csv rows to write in the test CSV file
        importer_class: class
            The importer class to be tested

        """

        __, cls.import_file_path = tempfile.mkstemp()

        # Write our CSV data into temp file
        with open(cls.import_file_path, 'w', encoding='utf-8') as import_file:
            csv_writer = csv.writer(import_file)
            csv_writer.writerows(csv_rows)

        # Instantiate our importer with the temp file path
        cls.importer = importer_class(file_path=cls.import_file_path)


class UserImporterTestCase(BaseImporterTestCase):
    """Test the ``UserImporter`` class"""

    @classmethod
    def setUpClass(cls):
        """Setup our test importer and CSV file"""

        super().setUpClass()

        csv_rows = []

        # Append the necessary number of empty rows
        for _ in range(1, config.SABA_USERS_IMPORT_OFFSET):
            csv_rows.append([])

        # Append fake data, one for create, one for update
        csv_rows += [[
            'FAKE_USERNAME',
            'FAKE_FIRST',
            'FAKE_LAST',
            'FAKE_EMAIL',
            'FAKE_PERSON_NO',
            'Français (French)',
            'France',
            'Sales',
            'D2SA Sales Advisor_FR',
            'Main Dealer Sales & After Sales',
            'FRA7845',
            'No',
            '',
            '1',
            '1',
        ], [
            cls.trainee.username,
            'NEW_TRAINEE_FIRST',
            'NEW_TRAINEE_LAST',
            'trainee@newemail.com',
            'FAKE_PERSON_NO',
            'Français (French)',
            'France',
            'Sales',
            'D2SA Sales Advisor_FR',
            'Main Dealer Sales & After Sales',
            'FRA7845',
            'No',
            '',
            '1',
            '1',
        ]]

        # we need those group types, they are used by the import mecanism
        for group_type_name in [
                GROUPTYPE_BUSINESS_LEVEL,
                GROUPTYPE_JOB_NAME,
                GROUPTYPE_JOB_TYPE,
                GROUPTYPE_BUSINESS_ZONE,
        ]:
            GroupTypeFactory(name=group_type_name)

        cls.setup_csv_test_file(csv_rows, UserImporter)

    def test_import_users(self):
        """Test the ``import_users`` method"""

        # Make sure the offset is correctly set to something else than default value
        self.assertNotEqual(self.importer.offset, 0)

        # Let's make sure out test assumption is correct
        self.assertNotEqual(self.trainee.username, self.trainee.external_id)

        # Import the users from our test CSV
        self.importer.import_users()

        # Create has worked
        new_user = MTPUser.objects.filter(username='FAKE_USERNAME').first()
        self.assertIsNotNone(new_user)
        self.assertEqual(new_user.first_name, 'FAKE_FIRST'.title())
        self.assertEqual(new_user.last_name, 'FAKE_LAST'.upper())
        self.assertEqual(new_user.external_id, new_user.username)

        # Update has worked
        self.trainee.refresh_from_db()
        self.assertEqual(self.trainee.first_name, 'NEW_TRAINEE_FIRST'.title())
        self.assertEqual(self.trainee.last_name, 'NEW_TRAINEE_LAST'.upper())
        self.assertEqual(self.trainee.email, 'trainee@newemail.com')
        self.assertEqual(self.trainee.username, self.trainee.external_id)


class CourseImporterTestCase(BaseImporterTestCase):
    """Test the ``CourseImporter`` class"""

    @classmethod
    def setUpClass(cls):
        """Setup our test importer and CSV file"""

        super().setUpClass()

        csv_rows = []

        # append the necessary number of empty rows
        for _ in range(1, config.SABA_COURSES_IMPORT_OFFSET):
            csv_rows.append([])

        # append fake data
        csv_rows += [[
            'FAKE_COURSE_ID',
            'FAKE_COURSE_TITLE',
        ], ]

        cls.setup_csv_test_file(csv_rows, CourseImporter)

    def test_import_courses(self):
        """Test the ``import_courses`` method"""

        # Make sure the offset is correctly set to something else than default value
        self.assertNotEqual(self.importer.offset, 0)

        # Let's make sure out test assumption is correct
        self.assertNotEqual(self.trainee.username, self.trainee.external_id)

        # Import the courses from our test CSV
        self.importer.import_courses()

        # We have a new lesson reference
        lesson_references = LessonReference.objects.filter(
            external_id='FAKE_COURSE_ID',
            external_name='FAKE_COURSE_TITLE',
        )
        self.assertEqual(lesson_references.count(), 1)
