"""Tests for Ollama status/model check endpoints in api_routes.py."""

from unittest.mock import patch, MagicMock

import requests

API_PREFIX = "/research/api"


class TestCheckOllamaStatus:
    """Tests for /check/ollama_status endpoint."""

    def test_requires_authentication(self, client):
        response = client.get(f"{API_PREFIX}/check/ollama_status")
        assert response.status_code in [401, 302]

    def test_non_ollama_provider_returns_running(self, authenticated_client):
        """When provider is not ollama, should return running=True."""
        with authenticated_client.application.test_request_context():
            authenticated_client.application.config["LLM_CONFIG"] = {
                "provider": "openai",
            }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_status")
        assert response.status_code == 200
        data = response.get_json()
        assert data["running"] is True
        assert (
            "openai" in data["message"].lower()
            or "not Ollama" in data["message"]
        )

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_ollama_running_new_api_format(
        self, mock_safe_get, authenticated_client
    ):
        """Ollama returns 200 with models list (new API format)."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {
            "models": [{"name": "llama3"}, {"name": "gemma3:12b"}]
        }
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_status")
        assert response.status_code == 200
        data = response.get_json()
        assert data["running"] is True
        assert data["model_count"] == 2

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_ollama_running_old_api_format(
        self, mock_safe_get, authenticated_client
    ):
        """Ollama returns 200 with array (old API format)."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = [{"name": "llama3"}]
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_status")
        data = response.get_json()
        assert data["running"] is True
        assert data["model_count"] == 1

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_ollama_invalid_json(self, mock_safe_get, authenticated_client):
        """Ollama returns 200 but invalid JSON."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.side_effect = ValueError("bad json")
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_status")
        data = response.get_json()
        assert data["running"] is True
        assert "invalid" in data["message"].lower()

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_ollama_non_200_status(self, mock_safe_get, authenticated_client):
        """Ollama returns non-200 status code."""
        mock_resp = MagicMock()
        mock_resp.status_code = 503
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_status")
        data = response.get_json()
        assert data["running"] is False
        assert data["status_code"] == 503

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_ollama_connection_error(self, mock_safe_get, authenticated_client):
        """Ollama connection refused."""
        mock_safe_get.side_effect = requests.exceptions.ConnectionError(
            "refused"
        )

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_status")
        data = response.get_json()
        assert data["running"] is False
        assert data["error_type"] == "connection_error"

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_ollama_timeout(self, mock_safe_get, authenticated_client):
        """Ollama request times out."""
        mock_safe_get.side_effect = requests.exceptions.Timeout("timed out")

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_status")
        data = response.get_json()
        assert data["running"] is False
        assert data["error_type"] == "timeout"


class TestCheckOllamaModel:
    """Tests for /check/ollama_model endpoint."""

    def test_requires_authentication(self, client):
        response = client.get(f"{API_PREFIX}/check/ollama_model")
        assert response.status_code in [401, 302]

    def test_non_ollama_provider(self, authenticated_client):
        """When provider is not ollama, should return available=True."""
        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "openai",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is True
        assert data["provider"] == "openai"

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_model_exists_new_format(self, mock_safe_get, authenticated_client):
        """Model exists in Ollama (new API format)."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {
            "models": [{"name": "llama3"}, {"name": "gemma3:12b"}]
        }
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "llama3",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is True
        assert data["model"] == "llama3"

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_model_not_found(self, mock_safe_get, authenticated_client):
        """Model not found in Ollama."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {"models": [{"name": "llama3"}]}
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "nonexistent-model",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is False
        assert "nonexistent-model" in data["message"]

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_no_models_available(self, mock_safe_get, authenticated_client):
        """Ollama has no models."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {"models": []}
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "llama3",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is False
        assert "no models" in data["message"].lower()

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_model_name_case_insensitive(
        self, mock_safe_get, authenticated_client
    ):
        """Model name comparison should be case-insensitive."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {"models": [{"name": "Llama3"}]}
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "llama3",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is True

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_model_from_query_param(self, mock_safe_get, authenticated_client):
        """Model name from query parameter overrides config."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {"models": [{"name": "custom-model"}]}
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "default-model",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(
            f"{API_PREFIX}/check/ollama_model?model=custom-model"
        )
        data = response.get_json()
        assert data["available"] is True
        assert data["model"] == "custom-model"

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_ollama_api_non_200(self, mock_safe_get, authenticated_client):
        """Ollama API returns non-200."""
        mock_resp = MagicMock()
        mock_resp.status_code = 500
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "llama3",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is False

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_json_parse_error(self, mock_safe_get, authenticated_client):
        """Ollama returns invalid JSON."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.side_effect = ValueError("bad json")
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "llama3",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is False
        assert data["error_type"] == "json_parse_error"

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_connection_error(self, mock_safe_get, authenticated_client):
        mock_safe_get.side_effect = requests.exceptions.ConnectionError(
            "refused"
        )

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "llama3",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is False
        assert data["error_type"] == "connection_error"

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_timeout_error(self, mock_safe_get, authenticated_client):
        mock_safe_get.side_effect = requests.exceptions.Timeout("timeout")

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "llama3",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is False
        assert data["error_type"] == "timeout"

    @patch("local_deep_research.web.routes.api_routes.safe_get")
    def test_old_api_format(self, mock_safe_get, authenticated_client):
        """Test with old Ollama API format (plain array)."""
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = [
            {"name": "llama3"},
            {"name": "codellama"},
        ]
        mock_safe_get.return_value = mock_resp

        authenticated_client.application.config["LLM_CONFIG"] = {
            "provider": "ollama",
            "model": "codellama",
            "ollama_base_url": "http://localhost:11434",
        }

        response = authenticated_client.get(f"{API_PREFIX}/check/ollama_model")
        data = response.get_json()
        assert data["available"] is True
