from unittest.mock import patch

import pytest
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIRequestFactory, force_authenticate

from company.models.company import Company
from company.models.location import LocationCode
from incident.models import Incident
from ncircc.enums.notifications import NotificationCategoryEnum, EventTypeEnum, NotificationStatusEnum
from ncircc.models.notification import Notification
from ncircc.serializers.notification import NotificationSerializer
from ncircc.tests.utils import mocked_notification_requests_post_status_201, \
    mocked_notification_requests_post_status_200
from ncircc.views.notification_api import NotificationApiViewSet


@pytest.mark.django_db
class TestNotificationApi:
    """ Test Notification Api View """

    @pytest.fixture(autouse=True)
    def setup_test(self, add_user_with_permissions):
        """Setup data for test"""
        self.incident = Incident.objects.create(title='test_inc', importance=10, event_count=10, events='')
        self.user = add_user_with_permissions(username='test_user', password='TesTPasWord1', is_superuser=True)
        self.notification = Notification.objects.create(
            incident=self.incident,
            category=NotificationCategoryEnum.INCIDENT.value,
            type=EventTypeEnum.SLOWDOWN_DUE_TO_DDOS.value,
            notification_status=NotificationStatusEnum.ADDITION_REQUIRED.value)
        location, _ = LocationCode.objects.get_or_create(code='RU-MOS')
        self.company = Company.objects.create(name='Test_name_1', city='Moscow', location=location)

    @pytest.mark.unit
    @patch('requests.post', side_effect=mocked_notification_requests_post_status_201)
    def test_create_api_valid(self, *args):
        """Test creating notification"""

        incident = Incident.objects.create(title='test_inc', importance=10, event_count=10, events='')
        count_before = Notification.objects.count()
        data = {
            'incident': incident.pk,
            "category": NotificationCategoryEnum.INCIDENT.value,
            "type": EventTypeEnum.SLOWDOWN_DUE_TO_DDOS.value,
            'event_description': 'description',
            'affected_system_name': 'name'
        }
        url = reverse('ncircc_notification-list')
        request = APIRequestFactory().post(url, data=data)
        view = NotificationApiViewSet.as_view({'post': 'create'})
        force_authenticate(request, self.user)
        response = view(request)
        count_after = Notification.objects.count()

        assert response.status_code == 201
        assert count_after == count_before + 1
        assert 'incident' in response.data
        assert response.data['incident'] == incident.pk
        fields = NotificationSerializer.Meta.fields
        for field in fields:
            assert field in response.data

    @pytest.mark.unit
    def test_get_list_api_valid(self):
        """Test valid getting notification list"""
        count = Notification.objects.count()
        url = reverse('ncircc_notification-list')
        request = APIRequestFactory().get(url)
        view = NotificationApiViewSet.as_view({'get': 'list'})
        force_authenticate(request, self.user)
        response = view(request)
        assert response.status_code == 200
        assert count == response.data.get('count')

    @pytest.mark.unit
    @patch('requests.post', side_effect=mocked_notification_requests_post_status_200)
    def test_update_api(self, *args):
        """Test valid updated notification"""
        data = {
            'type': EventTypeEnum.INVOLVING_INTO_MALWARE_INFRASTRUCTURE.value,
            'assistance': True,
            'incident': self.incident.pk,
            'category': NotificationCategoryEnum.INCIDENT.value,
            'event_description': 'description',
            'affected_system_name': 'name'
        }
        url = reverse('ncircc_notification-detail', args=[self.notification.pk])
        request = APIRequestFactory().patch(url, data)
        view = NotificationApiViewSet.as_view({'patch': 'update'})
        force_authenticate(request, self.user)
        response = view(request, pk=self.notification.pk)
        assert response.status_code == 200
        fields = NotificationSerializer.Meta.fields
        for field in fields:
            assert field in response.data

        notification = Notification.objects.get(pk=self.notification.pk)
        assert notification.assistance
        assert notification.type == 'Вовлечение контролируемого ресурса в инфраструктуру ВПО'

    @pytest.mark.unit
    @patch('requests.post', side_effect=mocked_notification_requests_post_status_200)
    def test_create_notification_with_same_incident(self, _, api_client):
        api_client.force_authenticate(self.user)
        url = reverse('ncircc_notification-list')
        data = {
            'incident': self.incident.pk,
            "category": NotificationCategoryEnum.INCIDENT.value,
            "type": EventTypeEnum.SLOWDOWN_DUE_TO_DDOS.value,
            'event_description': 'description',
            'affected_system_name': 'name'
        }
        response = api_client.post(url, data=data)
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert response.json() == {'incident': ["This field must be unique."]}  # already exists in setup_test

    @pytest.mark.unit
    def test_create_notification_without_required_field(self, api_client):
        api_client.force_authenticate(self.user)
        incident = Incident.objects.create(title='test_inc', importance=10, event_count=10, events='')
        url = reverse('ncircc_notification-list')
        data = {
            'incident': incident.pk,
            "category": NotificationCategoryEnum.INCIDENT.value,
            "type": EventTypeEnum.SLOWDOWN_DUE_TO_DDOS.value,
        }
        response = api_client.post(url, data=data)
        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert 'affected_system_name' in response.json()
        assert 'event_description' in response.json()
