"""Tests for research_routes module - Research page and API endpoints."""

from unittest.mock import patch, MagicMock


# Research routes are registered under root level
RESEARCH_PREFIX = ""

# Common patch target prefix for research_routes module
_RR = "local_deep_research.web.routes.research_routes"


class TestProgressPage:
    """Tests for /progress/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/progress/test-id")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return progress page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Progress</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/progress/test-id"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/progress.html")


class TestResearchDetailsPage:
    """Tests for /details/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/details/test-id")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return details page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Details</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/details/test-id"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/details.html")


class TestResultsPage:
    """Tests for /results/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/results/test-id")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return results page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Results</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/results/test-id"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/results.html")


class TestHistoryPage:
    """Tests for /history endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/history")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return history page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>History</html>"
            response = authenticated_client.get(f"{RESEARCH_PREFIX}/history")
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/history.html")


class TestSettingsPage:
    """Tests for /settings endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return settings page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Settings</html>"
            response = authenticated_client.get(f"{RESEARCH_PREFIX}/settings")
            assert response.status_code == 200
            mock_render.assert_called_once_with("settings_dashboard.html")


class TestMainConfigPage:
    """Tests for /settings/main endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/main")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return main config page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Main Config</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/settings/main"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("main_config.html")


class TestCollectionsConfigPage:
    """Tests for /settings/collections endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/collections")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return collections config page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Collections</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/settings/collections"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("collections_config.html")


class TestApiKeysConfigPage:
    """Tests for /settings/api_keys endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/api_keys")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return API keys config page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>API Keys</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/settings/api_keys"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("api_keys_config.html")


class TestSearchEnginesConfigPage:
    """Tests for /settings/search_engines endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/search_engines")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return search engines config page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Search Engines</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/settings/search_engines"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("search_engines_config.html")


class TestLlmConfigPage:
    """Tests for /settings/llm endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/llm")
        assert response.status_code in [401, 302, 404]

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return LLM config page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>LLM Config</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/settings/llm"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("llm_config.html")


class TestRedirectStatic:
    """Tests for /redirect-static/<path> endpoint."""

    def test_redirects_to_static(self, authenticated_client):
        """Should redirect to static URL."""
        with patch(f"{_RR}.url_for", return_value="/static/js/app.js"):
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/redirect-static/js/app.js"
            )
            # Should return a redirect response
            assert response.status_code == 302


class TestStartResearchApi:
    """Tests for /api/start_research endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.post(
            f"{RESEARCH_PREFIX}/api/start_research",
            json={"query": "test query"},
        )
        assert response.status_code in [401, 302, 404]

    def test_returns_401_without_session(self, authenticated_client):
        """Should return 401 when session has no username."""
        # Clear the session username
        with authenticated_client.session_transaction() as sess:
            sess.pop("username", None)

        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/start_research",
            json={"query": "test query"},
        )
        # Expects 401 since username is not in session
        assert response.status_code == 401

    def test_requires_json_body(self, authenticated_client):
        """Should require JSON body."""
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/start_research",
            data="not json",
            content_type="text/plain",
        )
        # Should return error for non-JSON body
        assert response.status_code in [400, 415, 500]


class TestTerminateResearchApi:
    """Tests for /api/terminate/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.post(f"{RESEARCH_PREFIX}/api/terminate/test-id")
        assert response.status_code in [401, 302, 404, 405]

    def test_returns_success_when_authenticated(self, authenticated_client):
        """Should handle terminate request when authenticated."""
        mock_research = MagicMock()
        mock_research.status = "in_progress"
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.post(
                f"{RESEARCH_PREFIX}/api/terminate/test-id"
            )
            assert response.status_code in [200, 404, 500]


class TestDeleteResearchApi:
    """Tests for /api/delete/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.delete(f"{RESEARCH_PREFIX}/api/delete/test-id")
        assert response.status_code in [401, 302, 404, 405]

    def test_returns_success_when_authenticated(self, authenticated_client):
        """Should handle delete request when authenticated."""
        mock_research = MagicMock()
        mock_research.status = "completed"
        mock_research.report_path = None
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.delete(
                f"{RESEARCH_PREFIX}/api/delete/test-id"
            )
            assert response.status_code in [200, 404, 500]


class TestClearHistoryApi:
    """Tests for /api/clear_history endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.post(f"{RESEARCH_PREFIX}/api/clear_history")
        assert response.status_code in [401, 302, 404, 405]

    def test_returns_success_when_authenticated(self, authenticated_client):
        """Should handle clear history request when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.all.return_value = []
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.post(
                f"{RESEARCH_PREFIX}/api/clear_history"
            )
            assert response.status_code in [200, 500]


class TestGetHistoryApi:
    """Tests for /api/history endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/history")
        assert response.status_code in [401, 302, 404]

    def test_returns_history_when_authenticated(self, authenticated_client):
        """Should return history when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.order_by.return_value.all.return_value = []
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/history"
            )
            assert response.status_code in [200, 500]


class TestGetResearchDetailsApi:
    """Tests for /api/research/<id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/research/test-id")
        assert response.status_code in [401, 302, 404]

    def test_returns_details_when_authenticated(self, authenticated_client):
        """Should return research details when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.filter.return_value.first.return_value = None
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/research/test-id"
            )
            assert response.status_code in [200, 404, 500]


class TestGetResearchLogsApi:
    """Tests for /api/research/<id>/logs endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/research/test-id/logs")
        assert response.status_code in [401, 302, 404]

    def test_returns_logs_when_authenticated(self, authenticated_client):
        """Should return research logs when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = None
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/research/test-id/logs"
            )
            assert response.status_code in [200, 404, 500]


class TestGetResearchStatusApi:
    """Tests for /api/research/<id>/status endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/research/test-id/status")
        assert response.status_code in [401, 302, 404]

    def test_returns_status_when_authenticated(self, authenticated_client):
        """Should return research status when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = None
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/research/test-id/status"
            )
            assert response.status_code in [200, 404, 500]


class TestQueueStatusApi:
    """Tests for queue status API endpoints."""

    def test_get_queue_status_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/queue/status")
        assert response.status_code in [401, 302, 404]

    def test_get_queue_status_when_authenticated(self, authenticated_client):
        """Should return queue status when authenticated."""
        with patch("local_deep_research.web.queue.QueueManager") as mock_qm:
            mock_qm.get_user_queue.return_value = []
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/queue/status"
            )
            assert response.status_code in [200, 500]

    def test_get_queue_position_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/queue/test-id/position")
        assert response.status_code in [401, 302, 404]
