from mock import patch, MagicMock, Mock

from atheneum.middleware.authentication_middleware import \
    authenticate_with_password, authenticate_with_token

middleware_module = 'atheneum.middleware.authentication_middleware'


@patch(middleware_module + '.g')
@patch(middleware_module + '.authentication_service.is_valid_password')
@patch(middleware_module + '.user_service.find_by_name')
def test_authenticate_with_password_happy_path(
        mock_user_service: MagicMock,
        mock_authentication_service: MagicMock,
        mock_g: MagicMock):
    mock_g.user = Mock()
    mock_user_service.return_value = Mock()
    mock_authentication_service.return_value = True
    assert authenticate_with_password('test', 'test')
    mock_user_service.assert_called_once()
    mock_authentication_service.assert_called_once()
    mock_g.user.assert_not_called()


@patch(middleware_module + '.g')
@patch(middleware_module + '.authentication_service.is_valid_password')
@patch(middleware_module + '.user_service.find_by_name')
def test_authenticate_with_password_no_user(
        mock_user_service: MagicMock,
        mock_authentication_service: MagicMock,
        mock_g: MagicMock):
    mock_g.user = Mock()
    mock_user_service.return_value = None
    mock_authentication_service.return_value = True
    assert not authenticate_with_password('test', 'test')
    mock_user_service.assert_called_once()
    mock_authentication_service.assert_not_called()
    mock_g.user.assert_not_called()


@patch(middleware_module + '.g')
@patch(middleware_module + '.authentication_service.is_valid_password')
@patch(middleware_module + '.user_service.find_by_name')
def test_authenticate_with_password_invalid_password(
        mock_user_service: MagicMock,
        mock_authentication_service: MagicMock,
        mock_g: MagicMock):
    mock_g.user = Mock()
    mock_user_service.return_value = Mock()
    mock_authentication_service.return_value = False
    assert not authenticate_with_password('test', 'test')
    mock_user_service.assert_called_once()
    mock_authentication_service.assert_called_once()
    mock_g.user.assert_not_called()


@patch(middleware_module + '.g')
@patch(middleware_module + '.authentication_service.is_valid_token')
@patch(middleware_module + '.user_token_service.find_by_user_and_token')
@patch(middleware_module + '.user_service.find_by_name')
def test_authenticate_with_token_happy_path(
        mock_user_service: MagicMock,
        mock_user_token_service: MagicMock,
        mock_authentication_service: MagicMock,
        mock_g: MagicMock):
    mock_g.user = Mock()
    mock_user_service.return_value = Mock()
    mock_user_token_service.return_value = Mock()
    mock_authentication_service.return_value = True
    assert authenticate_with_token('test', 'test')
    mock_user_service.assert_called_once()
    mock_user_token_service.assert_called_once()
    mock_authentication_service.assert_called_once()
    mock_g.user.assert_not_called()


@patch(middleware_module + '.g')
@patch(middleware_module + '.authentication_service.is_valid_token')
@patch(middleware_module + '.user_token_service.find_by_user_and_token')
@patch(middleware_module + '.user_service.find_by_name')
def test_authenticate_with_token_no_user(
        mock_user_service: MagicMock,
        mock_user_token_service: MagicMock,
        mock_authentication_service: MagicMock,
        mock_g: MagicMock):
    mock_g.user = Mock()
    mock_user_service.return_value = None
    assert not authenticate_with_token('test', 'test')
    mock_user_service.assert_called_once()
    mock_user_token_service.assert_not_called()
    mock_authentication_service.assert_not_called()
    mock_g.user.assert_not_called()


@patch(middleware_module + '.g')
@patch(middleware_module + '.authentication_service.is_valid_token')
@patch(middleware_module + '.user_token_service.find_by_user_and_token')
@patch(middleware_module + '.user_service.find_by_name')
def test_authenticate_with_token_no_user_token(
        mock_user_service: MagicMock,
        mock_user_token_service: MagicMock,
        mock_authentication_service: MagicMock,
        mock_g: MagicMock):
    mock_g.user = Mock()
    mock_user_service.return_value = Mock()
    mock_user_token_service.return_value = None
    mock_authentication_service.return_value = False
    assert not authenticate_with_token('test', 'test')
    mock_user_service.assert_called_once()
    mock_user_token_service.assert_called_once()
    mock_authentication_service.assert_called_once()
    mock_g.user.assert_not_called()


@patch(middleware_module + '.g')
@patch(middleware_module + '.authentication_service.is_valid_token')
@patch(middleware_module + '.user_token_service.find_by_user_and_token')
@patch(middleware_module + '.user_service.find_by_name')
def test_authenticate_with_token_invalid_token(
        mock_user_service: MagicMock,
        mock_user_token_service: MagicMock,
        mock_authentication_service: MagicMock,
        mock_g: MagicMock):
    mock_g.user = Mock()
    mock_user_service.return_value = Mock()
    mock_user_token_service.return_value = Mock()
    mock_authentication_service.return_value = False
    assert not authenticate_with_token('test', 'test')
    mock_user_service.assert_called_once()
    mock_user_token_service.assert_called_once()
    mock_authentication_service.assert_called_once()
    mock_g.user.assert_not_called()