"""Unit tests for template rest api
"""

from unittest.mock import patch, MagicMock

from django.test import SimpleTestCase
from rest_framework import status
from tests.components.data.tests_unit import _get_template, _get_json_template

import core_main_app.components.template.api as template_api
from core_main_app.access_control.exceptions import AccessControlError
from core_main_app.commons.exceptions import DoesNotExist
from core_main_app.components.template.models import Template
from core_main_app.rest.template import views as template_rest_views
from core_main_app.utils.tests_tools.MockUser import create_mock_user
from core_main_app.utils.tests_tools.RequestMock import RequestMock


class TestTemplateDownload(SimpleTestCase):
    """Test Template Download"""

    def setUp(self):
        """setUp"""

        super().setUp()

    @patch.object(template_api, "get_by_id")
    def test_get_returns_http_404_when_data_not_found(
        self, mock_template_api_get_by_id
    ):
        """test_get_returns_http_404_when_data_not_found"""

        # Arrange
        mock_user = create_mock_user("1")
        mock_template_api_get_by_id.side_effect = DoesNotExist("error")

        # Mock
        response = RequestMock.do_request_get(
            template_rest_views.TemplateDownload.as_view(),
            mock_user,
            param={"pk": "1"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    @patch.object(template_api, "get_by_id")
    def test_get_returns_http_200_when_data_found(
        self, mock_template_api_get_by_id
    ):
        """test_get_returns_http_200_when_data_found"""

        # Arrange
        mock_user = create_mock_user("1")
        mock_template = _get_template()
        mock_template_api_get_by_id.return_value = mock_template

        # Mock
        response = RequestMock.do_request_get(
            template_rest_views.TemplateDownload.as_view(),
            mock_user,
            param={"pk": "1"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    @patch.object(template_api, "get_by_id")
    def test_get_returns_http_400_when_data_not_well_formatted(
        self, mock_template_api_get_by_id
    ):
        """test_get_returns_http_400_when_data_not_well_formatted"""

        # Arrange
        mock_user = create_mock_user("1")
        mock_template = Template()
        mock_template.content = "/test"
        mock_template_api_get_by_id.return_value = mock_template

        # Mock
        response = RequestMock.do_request_get(
            template_rest_views.TemplateDownload.as_view(),
            mock_user,
            param={"pk": "1"},
            data={"pretty_print": "true"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch.object(template_api, "get_by_id")
    def test_get_without_pretty_print_returns_data(
        self, mock_template_api_get_by_id
    ):
        """test_get_without_pretty_print_returns_data"""

        # Arrange
        mock_user = create_mock_user("1")
        mock_template = _get_template()
        mock_template_api_get_by_id.return_value = mock_template
        expected_value = b'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:element name="tag"></xs:element></xs:schema>'
        # Mock
        response = RequestMock.do_request_get(
            template_rest_views.TemplateDownload.as_view(),
            mock_user,
            param={"pk": "1"},
            data={"pretty_print": "false"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.content, expected_value)

    @patch.object(template_api, "get_by_id")
    def test_get_with_pretty_print_returns_formatted_data(
        self, mock_template_api_get_by_id
    ):
        """test_get_with_pretty_print_returns_formatted_data"""

        # Arrange
        mock_user = create_mock_user("1")
        mock_template = _get_template()
        mock_template_api_get_by_id.return_value = mock_template
        expected_value = b'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">\n  <xs:element name="tag"/>\n</xs:schema>\n'

        # Mock
        response = RequestMock.do_request_get(
            template_rest_views.TemplateDownload.as_view(),
            mock_user,
            param={"pk": "1"},
            data={"pretty_print": "true"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.content, expected_value)

    @patch.object(template_api, "get_by_id")
    def test_get_with_pretty_print_json_returns_formatted_template(
        self, mock_template_api_get_by_id
    ):
        """test_get_with_pretty_print_json_returns_formatted_template

        Args:
            mock_template_api_get_by_id:

        Returns:

        """
        # Arrange
        mock_user = create_mock_user("1")
        mock_template = _get_json_template()
        mock_template_api_get_by_id.return_value = mock_template
        expected_value = b"{}"

        # Mock
        response = RequestMock.do_request_get(
            template_rest_views.TemplateDownload.as_view(),
            mock_user,
            param={"pk": "1"},
            data={"pretty_print": "true"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.content, expected_value)

    @patch.object(template_api, "get_by_id")
    def test_get_with_pretty_unknown_template_format_return_bad_response(
        self, mock_template_api_get_by_id
    ):
        """test_get_with_pretty_unknown_template_format_return_bad_response

        Args:
            mock_template_api_get_by_id:

        Returns:

        """
        # Arrange
        mock_user = create_mock_user("1")
        mock_template = _get_json_template()
        mock_template.format = "BAD"
        mock_template_api_get_by_id.return_value = mock_template

        # Mock
        response = RequestMock.do_request_get(
            template_rest_views.TemplateDownload.as_view(),
            mock_user,
            param={"pk": "1"},
            data={"pretty_print": "true"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)


class TestTemplateList(SimpleTestCase):
    @patch.object(template_api, "get_all")
    def test_get_returns_http_200(self, mock_template_api_get_all):
        # Arrange
        mock_user = create_mock_user("1")
        mock_template_api_get_all.return_value = MagicMock()

        # Act
        response = RequestMock.do_request_get(
            template_rest_views.TemplateList.as_view(),
            mock_user,
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    @patch.object(template_api, "get_all")
    def test_get_with_filename_filter_returns_http_200(
        self, mock_template_api_get_all
    ):
        # Arrange
        mock_user = create_mock_user("1")
        mock_template_api_get_all.return_value = MagicMock()

        # Act
        response = RequestMock.do_request_get(
            template_rest_views.TemplateList.as_view(),
            mock_user,
            data={"filename": "example.xsd"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    @patch.object(template_api, "get_all")
    def test_get_with_invalid_template_format_returns_http_400(
        self, mock_template_api_get_all
    ):
        # Arrange
        mock_user = create_mock_user("1")
        mock_template_api_get_all.return_value = MagicMock()

        # Act
        response = RequestMock.do_request_get(
            template_rest_views.TemplateList.as_view(),
            mock_user,
            data={"template_format": "INVALID"},
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    @patch.object(template_api, "get_all")
    def test_get_with_access_control_error_returns_http_403(
        self, mock_template_api_get_all
    ):
        # Arrange
        mock_user = create_mock_user("1")
        mock_template_api_get_all.side_effect = AccessControlError("Error")

        # Act
        response = RequestMock.do_request_get(
            template_rest_views.TemplateList.as_view(),
            mock_user,
        )

        # Assert
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    @patch.object(template_api, "get_all")
    def test_get_with_exception_returns_http_500(
        self, mock_template_api_get_all
    ):
        # Arrange
        mock_user = create_mock_user("1")
        mock_template_api_get_all.side_effect = Exception("Error")

        # Act
        response = RequestMock.do_request_get(
            template_rest_views.TemplateList.as_view(),
            mock_user,
        )

        # Assert
        self.assertEqual(
            response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR
        )
