from unittest.mock import patch

import pytest
from rest_framework.reverse import reverse

from core.services.amc_services import AMCServiceException, AMCService


def mock_subprocess(code=0, stdout=b'', stderr=b''):
    class MockSubprocessRun:
        def __init__(self, *args, **kwargs):
            self.returncode = code
            self.stdout = stdout
            self.stderr = stderr

    return MockSubprocessRun


class TestManageService:

    @pytest.fixture(autouse=True)
    def setup_tests(self, django_user_model):
        self.user = django_user_model.objects.get()

    def test_receive_invalid_service(self):
        service_name = 'test'
        with pytest.raises(AMCServiceException) as exc:
            AMCService(service_name)
        assert exc.value.detail['status'] == 'error'
        assert exc.value.detail['detail'] == f'Unable to work with "{service_name}" service'

    @patch('core.services.amc_services.subprocess.run', mock_subprocess(stdout=b'active'))
    def test_get_status_service(self):
        service = AMCService('nginx')
        assert service.get_status() == 'active'

    @patch('core.services.amc_services.subprocess.run', mock_subprocess(code=5, stderr=b'error'))
    def test_unable_to_get_status_service(self):
        service_name = 'nginx'
        service = AMCService(service_name)
        with pytest.raises(AMCServiceException) as exc:
            service.get_status()
        assert exc.value.detail['status'] == 'error'
        assert exc.value.detail['detail'] == f"Can't get status '{service_name}': error"

    @patch('core.services.amc_services.subprocess.run', mock_subprocess())
    def test_reboot_service(self):
        service_name = 'nginx'
        service = AMCService(service_name)
        assert service.reboot() == ''  # it is correct stdout response

    @patch('core.services.amc_services.subprocess.run', mock_subprocess(stdout=b'active'))
    def test_api_get_status_service(self, api_client):
        api_client.force_authenticate(self.user)
        response = api_client.get(reverse('amc-status', kwargs={'service_name': 'nginx'}))
        assert response.json() == {'status': 'active'}

    @patch('core.services.amc_services.subprocess.run', mock_subprocess(code=1))
    def test_api_get_status_service_with_error(self, api_client):
        api_client.force_authenticate(self.user)
        response = api_client.get(reverse('amc-status',  params={'service_name': 'nginx'}))
        assert response.json() == {'status': 'error', 'detail': f"Can't get status 'nginx': "}

    @patch('core.services.amc_services.subprocess.run', mock_subprocess())
    def test_api_reboot_service(self, api_client):
        api_client.force_authenticate(self.user)
        response = api_client.get(reverse('amc-reboot', kwargs={'service_name': 'nginx'}))
        assert response.json() == {'status': 'ok'}

    @patch('core.services.amc_services.subprocess.run', mock_subprocess(code=1))
    def test_api_reboot_service_with_error(self, api_client):
        api_client.force_authenticate(self.user)
        response = api_client.get(reverse('amc-reboot', kwargs={'service_name': 'nginx'}))
        assert response.json() == {'status': 'error', 'detail': f"Can't reboot 'nginx': "}

    @patch('core.services.amc_services.subprocess.run', mock_subprocess(code=1))
    def test_api_get_status_with_invalid_service(self, api_client):
        api_client.force_authenticate(self.user)
        response = api_client.get(reverse('amc-status', kwargs={'service_name': 'invalid'}))
        assert response.json() == {'status': 'error', 'detail': f'Unable to work with "invalid" service'}
