import uuid
from unittest.mock import patch

import pytest

from company.models.company import Company
from incident.models import Incident
from ncircc.enums.notifications import EventTypeEnum
from ncircc.models.comments import Comment
from ncircc.models.notification import Notification
from ncircc.services.comments import CommentSenderService, CommentSuccessDataResponse, CommentsUpdaterService
from ncircc.tests.utils import mock_comments_request_post_status_200, mocked_notification_requests_post_status_400, \
    mock_comments_request_get_all_200


@pytest.mark.django_db
class TestCommentsServices:
    message = 'Test text'
    uuid = 'dd6dda3b-68ee-4885-9186-b5fc56ab3f03'

    @pytest.fixture(autouse=True)
    def setup_test(self, add_user_with_permissions) -> None:
        self.user = add_user_with_permissions(username='username1', password='PasSwor1d1', is_superuser=True)
        self.company = Company.objects.create(name='Test_name', api_key='test_api_key', city='Moscow')
        self.incident = Incident.objects.create(title='test_inc_1', importance=10, event_count=10, events='')

        self.notification = Notification.objects.create(
            incident=self.incident,
            affected_system_name='affected_system_name_test',
            event_description='event_description_test',
            type=EventTypeEnum.INVOLVING_INTO_MALWARE_INFRASTRUCTURE.value,
            uuid=self.uuid
        )

    @pytest.mark.unit
    def test_get_payload_for_comments(self):
        sender = CommentSenderService(self.message, self.notification.pk, self.user)
        payload = sender.get_payload()
        assert isinstance(payload, dict)
        assert 'incident.uuid' in payload
        assert isinstance(payload['incident.uuid'], str)
        assert 'data' in payload
        assert 'comment' in payload['data']
        assert payload['data']['comment'] == self.message

    @pytest.mark.unit
    @patch('requests.post', side_effect=mock_comments_request_post_status_200)
    def test_send_valid_comment(self, *args):
        before_comments_count = Comment.objects.count()
        assert not before_comments_count

        sender = CommentSenderService(self.message, self.notification.pk, self.user)
        msg, status = sender.send()

        assert status == 200
        assert isinstance(msg, dict)
        assert 'id' in msg
        assert 'text' in msg
        assert msg['text'] == self.message
        assert 'create_time' in msg
        assert 'login' in msg
        assert 'notification' in msg
        assert msg['notification'] == self.notification.pk
        assert 'id_in_ncircc' in msg
        assert 'from_console' in msg
        assert msg['from_console']
        assert 'is_read' in msg
        assert msg['is_read']
        after_comments_count = Comment.objects.count()
        assert after_comments_count == 1

    @pytest.mark.unit
    @patch('requests.post', side_effect=mocked_notification_requests_post_status_400)
    def test_send_not_valid_comment(self, *args):
        sender = CommentSenderService(self.message, self.notification.pk, self.user)
        msg, status = sender.send()
        assert status == 400
        assert msg == 'Error'

    @pytest.mark.unit
    def test_save(self):
        message = 'Test text'
        sender = CommentSenderService(message, self.notification.pk, self.user)
        data = mock_comments_request_post_status_200().json()
        sender._save(CommentSuccessDataResponse(**data.get('data', {})))
        comment = Comment.objects.last()
        assert comment
        assert comment.text == message
        assert comment.login == self.user.username
        assert comment.create_time
        assert comment.from_console

    @pytest.mark.unit
    @patch('requests.get', side_effect=mock_comments_request_get_all_200)
    def test_comments_updater(self, *args):
        """ Test CommentsUpdaterService"""
        count_count_before = Comment.objects.count()
        assert not count_count_before
        updater = CommentsUpdaterService()
        updater.send()
        comments = Comment.objects.all()
        assert len(comments) == 3
        for comment in comments:
            assert comment.notification.pk == self.notification.pk
            assert not comment.from_console



