from unittest import mock

import pytest


class TestReserveGraceidValidation:
    """Tests for _reserve_graceid error checking."""

    def test_wrong_api_version(self, safe_client):
        """Raises NotImplementedError when api_version is not v2."""
        with pytest.raises(NotImplementedError,
                           match="only implemented in API v2"):
            safe_client._reserve_graceid('CBC', 'gstlal')

    def test_missing_template(self, v2_client):
        """Raises NotImplementedError when server lacks the template."""
        mock_template_dict = {'event-detail-template': 'http://example.com'}
        template_prop = 'ligo.gracedb.rest.GraceDb.templates'

        with mock.patch(template_prop, mock_template_dict):
            with pytest.raises(NotImplementedError,
                               match="not yet implemented on"):
                v2_client._reserve_graceid('CBC', 'gstlal')

    def test_templates_is_none(self, v2_client):
        """Raises NotImplementedError when templates is None."""
        template_prop = 'ligo.gracedb.rest.GraceDb.templates'

        with mock.patch(template_prop, None):
            with pytest.raises(NotImplementedError,
                               match="not yet implemented on"):
                v2_client._reserve_graceid('CBC', 'gstlal')


class TestReserveGraceidPost:
    """Tests for _reserve_graceid successful POST."""

    def test_post_with_required_fields(self, v2_client):
        """POST is called with group and pipeline in data."""
        uri = 'http://example.com/api/v2/events/reserve/'
        mock_template_dict = {'event-reserve-template': uri}
        template_prop = 'ligo.gracedb.rest.GraceDb.templates'

        with mock.patch('ligo.gracedb.rest.GraceDb.post') as mock_post, \
             mock.patch(template_prop, mock_template_dict):
            v2_client._reserve_graceid('CBC', 'gstlal')

        mock_post.assert_called_once_with(uri, data={
            'group': 'CBC',
            'pipeline': 'gstlal',
        })

    def test_post_with_search(self, v2_client):
        """POST includes search when provided."""
        uri = 'http://example.com/api/v2/events/reserve/'
        mock_template_dict = {'event-reserve-template': uri}
        template_prop = 'ligo.gracedb.rest.GraceDb.templates'

        with mock.patch('ligo.gracedb.rest.GraceDb.post') as mock_post, \
             mock.patch(template_prop, mock_template_dict):
            v2_client._reserve_graceid('CBC', 'gstlal', search='AllSky')

        mock_post.assert_called_once_with(uri, data={
            'group': 'CBC',
            'pipeline': 'gstlal',
            'search': 'AllSky',
        })

    def test_post_without_search(self, v2_client):
        """POST omits search when not provided."""
        uri = 'http://example.com/api/v2/events/reserve/'
        mock_template_dict = {'event-reserve-template': uri}
        template_prop = 'ligo.gracedb.rest.GraceDb.templates'

        with mock.patch('ligo.gracedb.rest.GraceDb.post') as mock_post, \
             mock.patch(template_prop, mock_template_dict):
            v2_client._reserve_graceid('CBC', 'gstlal')

        call_args, call_kwargs = mock_post.call_args
        assert 'search' not in call_kwargs['data']

    def test_returns_post_response(self, v2_client):
        """Returns the response from post()."""
        uri = 'http://example.com/api/v2/events/reserve/'
        mock_template_dict = {'event-reserve-template': uri}
        template_prop = 'ligo.gracedb.rest.GraceDb.templates'

        with mock.patch('ligo.gracedb.rest.GraceDb.post') as mock_post, \
             mock.patch(template_prop, mock_template_dict):
            result = v2_client._reserve_graceid('CBC', 'gstlal')

        assert result == mock_post.return_value
