"""Tests for mldash._api — HTTP helpers for ML-Dash API."""
import pytest
from unittest.mock import MagicMock, patch

from mldash._api import _get, fetch_models, fetch_projects, resolve_project_by_name
from mldash._errors import MLDashAuthError, MLDashUploadError


class TestGet:
    @patch('mldash._api.requests.get')
    def test_successful_get(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {'results': []}
        mock_get.return_value = mock_resp

        result = _get('/api/projects/', 'http://localhost:8000', 'mldash_key')
        assert result == {'results': []}
        mock_get.assert_called_once_with(
            'http://localhost:8000/api/projects/',
            headers={'X-API-Key': 'mldash_key'},
            params=None,
            timeout=15,
        )

    @patch('mldash._api.requests.get')
    def test_with_params(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {'results': []}
        mock_get.return_value = mock_resp

        _get('/api/models/', 'http://localhost:8000', 'mldash_key', params={'project': '5'})
        assert mock_get.call_args.kwargs['params'] == {'project': '5'}

    @patch('mldash._api.requests.get')
    def test_strips_trailing_slash(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {}
        mock_get.return_value = mock_resp

        _get('/api/test/', 'http://localhost:8000/', 'mldash_key')
        assert mock_get.call_args.args[0] == 'http://localhost:8000/api/test/'

    @patch('mldash._api.requests.get')
    def test_auth_error_401(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 401
        mock_get.return_value = mock_resp

        with pytest.raises(MLDashAuthError, match='Invalid API key'):
            _get('/api/test/', 'http://localhost:8000', 'mldash_bad')

    @patch('mldash._api.requests.get')
    def test_auth_error_403(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 403
        mock_get.return_value = mock_resp

        with pytest.raises(MLDashAuthError, match='not authorized'):
            _get('/api/test/', 'http://localhost:8000', 'mldash_bad')

    @patch('mldash._api.requests.get')
    def test_server_error(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 500
        mock_resp.json.return_value = {'error': 'Server error'}
        mock_get.return_value = mock_resp

        with pytest.raises(MLDashUploadError, match='500'):
            _get('/api/test/', 'http://localhost:8000', 'mldash_key')

    @patch('mldash._api.requests.get')
    def test_connection_error(self, mock_get):
        import requests as req
        mock_get.side_effect = req.ConnectionError('refused')

        with pytest.raises(MLDashUploadError, match='Could not connect'):
            _get('/api/test/', 'http://localhost:8000', 'mldash_key')


class TestFetchProjects:
    @patch('mldash._api.requests.get')
    def test_returns_results(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {
            'results': [
                {'id': 1, 'name': 'Project A'},
                {'id': 2, 'name': 'Project B'},
            ]
        }
        mock_get.return_value = mock_resp

        projects = fetch_projects('http://localhost:8000', 'mldash_key')
        assert len(projects) == 2
        assert projects[0]['name'] == 'Project A'

    @patch('mldash._api.requests.get')
    def test_returns_empty_when_no_results(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {'results': []}
        mock_get.return_value = mock_resp

        assert fetch_projects('http://localhost:8000', 'mldash_key') == []


class TestFetchModels:
    @patch('mldash._api.requests.get')
    def test_returns_models(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {
            'results': [{'id': 1, 'name': 'Model A'}]
        }
        mock_get.return_value = mock_resp

        models = fetch_models('http://localhost:8000', 'mldash_key')
        assert len(models) == 1

    @patch('mldash._api.requests.get')
    def test_passes_project_filter(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {'results': []}
        mock_get.return_value = mock_resp

        fetch_models('http://localhost:8000', 'mldash_key', project_id=5)
        assert mock_get.call_args.kwargs['params'] == {'project': '5'}

    @patch('mldash._api.requests.get')
    def test_no_project_filter(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {'results': []}
        mock_get.return_value = mock_resp

        fetch_models('http://localhost:8000', 'mldash_key')
        assert mock_get.call_args.kwargs['params'] == {}


class TestResolveProjectByName:
    @patch('mldash._api.requests.get')
    def test_finds_project(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {
            'results': [
                {'id': 1, 'name': 'Churn'},
                {'id': 2, 'name': 'Sales'},
            ]
        }
        mock_get.return_value = mock_resp

        assert resolve_project_by_name('http://localhost:8000', 'mldash_key', 'Sales') == 2

    @patch('mldash._api.requests.get')
    def test_returns_none_when_not_found(self, mock_get):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {'results': [{'id': 1, 'name': 'Churn'}]}
        mock_get.return_value = mock_resp

        assert resolve_project_by_name('http://localhost:8000', 'mldash_key', 'Nope') is None
