"""
Tests to verify session["username"] hardening across all route files.

All @login_required route handlers should use session["username"] (direct access)
instead of session.get("username"). The @login_required decorator guarantees
the key exists; direct access fails fast if the decorator is ever removed.
"""

import inspect
import textwrap


def _get_function_source(func):
    """Get dedented source of a function for AST analysis."""
    return textwrap.dedent(inspect.getsource(func))


def _uses_unsafe_session_get(source: str) -> bool:
    """Check if source contains session.get("username") or flask_session.get("username")."""
    return (
        'session.get("username")' in source
        or "session.get('username')" in source
    )


def _uses_safe_session_access(source: str) -> bool:
    """Check if source contains session["username"] or flask_session["username"]."""
    return 'session["username"]' in source or "session['username']" in source


class TestNewsRoutesSessionAccess:
    """Verify news routes use session['username'] not session.get('username')."""

    def _get_route_functions(self):
        from local_deep_research.web.routes.news_routes import (
            create_subscription,
            get_news_feed,
            get_subscriptions,
            save_preferences,
            submit_feedback,
        )

        return [
            get_news_feed,
            get_subscriptions,
            create_subscription,
            submit_feedback,
            save_preferences,
        ]

    def test_no_session_get_username(self):
        """No news route should use session.get('username')."""
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username') "
                f"instead of session['username']"
            )

    def test_uses_session_bracket_access(self):
        """Each news route that accesses username should use bracket notation."""
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert _uses_safe_session_access(source), (
                f"{func.__name__} should use session['username']"
            )


class TestHistoryRoutesSessionAccess:
    """Verify history routes use session['username'] not session.get('username')."""

    def _get_route_functions(self):
        from local_deep_research.web.routes.history_routes import (
            get_history,
            get_research_details,
            get_research_logs,
            get_research_status,
        )

        return [
            get_history,
            get_research_status,
            get_research_details,
            get_research_logs,
        ]

    def test_no_session_get_username(self):
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username')"
            )


class TestResearchRoutesSessionAccess:
    """Verify research routes use session['username'] not session.get('username')."""

    def _get_route_functions(self):
        from local_deep_research.web.routes.research_routes import (
            clear_history,
            delete_research,
            export_research_report,
            get_history,
            get_queue_position,
            get_queue_status,
            get_research_details,
            get_research_logs,
            get_research_report,
            get_research_status,
            start_research,
            terminate_research,
            upload_pdf,
        )

        return [
            start_research,
            terminate_research,
            delete_research,
            clear_history,
            get_history,
            get_research_details,
            get_research_logs,
            get_research_report,
            export_research_report,
            get_research_status,
            get_queue_status,
            get_queue_position,
            upload_pdf,
        ]

    def test_no_session_get_username(self):
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username')"
            )


class TestContextOverflowSessionAccess:
    """Verify context overflow routes use flask_session['username']."""

    def test_no_session_get_username(self):
        from local_deep_research.web.routes.context_overflow_api import (
            get_context_overflow_metrics,
        )

        source = _get_function_source(get_context_overflow_metrics)
        assert not _uses_unsafe_session_get(source), (
            "get_context_overflow_metrics uses session.get('username')"
        )


class TestApiRoutesSessionAccess:
    """Verify API routes use session['username']."""

    def test_no_session_get_username(self):
        from local_deep_research.web.routes.api_routes import (
            api_terminate_research,
        )

        source = _get_function_source(api_terminate_research)
        assert not _uses_unsafe_session_get(source), (
            "api_terminate_research uses session.get('username')"
        )


class TestSettingsRoutesSessionAccess:
    """Verify settings routes use session['username'] (except helper functions)."""

    def _get_route_functions(self):
        from local_deep_research.web.routes.settings_routes import (
            api_delete_setting,
            api_get_all_settings,
            api_get_available_models,
            api_get_available_search_engines,
            api_get_categories,
            api_get_db_setting,
            api_get_search_favorites,
            api_import_settings,
            api_toggle_search_favorite,
            api_update_search_favorites,
            api_update_setting,
            fix_corrupted_settings,
            reset_to_defaults,
            save_all_settings,
            save_settings,
        )

        return [
            save_all_settings,
            reset_to_defaults,
            save_settings,
            api_get_all_settings,
            api_get_db_setting,
            api_update_setting,
            api_delete_setting,
            api_import_settings,
            api_get_categories,
            api_get_available_models,
            api_get_available_search_engines,
            api_get_search_favorites,
            api_update_search_favorites,
            api_toggle_search_favorite,
            fix_corrupted_settings,
        ]

    def test_no_session_get_username_in_routes(self):
        """Decorated route functions should not use session.get('username')."""
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username')"
            )

    def test_helper_functions_use_safe_get(self):
        """Helper functions (not decorated) should still use session.get('username')."""
        from local_deep_research.web.routes.settings_routes import (
            _get_setting_from_session,
        )
        from local_deep_research.web.warning_checks import calculate_warnings

        for func in [_get_setting_from_session, calculate_warnings]:
            source = _get_function_source(func)
            assert _uses_unsafe_session_get(source), (
                f"{func.__name__} should use session.get('username') "
                f"because it is not behind @login_required"
            )


class TestLibraryRoutesSessionAccess:
    """Verify library routes use session['username']."""

    def _get_route_functions(self):
        from local_deep_research.research_library.routes.library_routes import (
            check_downloads,
            delete_document,
            document_details_page,
            download_all_text,
            download_bulk,
            download_research_pdfs,
            download_single_resource,
            download_source,
            download_text_single,
            get_collections_list,
            get_documents,
            get_library_stats,
            get_research_list,
            get_research_sources,
            library_page,
            mark_for_redownload,
            download_manager_page,
            queue_all_undownloaded,
            serve_text_api,
            sync_library,
            toggle_favorite,
            view_pdf_page,
            view_text_page,
        )

        return [
            library_page,
            document_details_page,
            download_manager_page,
            get_library_stats,
            get_collections_list,
            get_documents,
            toggle_favorite,
            delete_document,
            view_pdf_page,
            view_text_page,
            serve_text_api,
            download_single_resource,
            download_text_single,
            download_all_text,
            download_research_pdfs,
            download_bulk,
            get_research_list,
            sync_library,
            mark_for_redownload,
            queue_all_undownloaded,
            get_research_sources,
            check_downloads,
            download_source,
        ]

    def test_no_session_get_username(self):
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username')"
            )


class TestFollowupRoutesSessionAccess:
    """Verify followup routes use session['username']."""

    def test_no_session_get_username(self):
        from local_deep_research.followup_research.routes import (
            prepare_followup,
            start_followup,
        )

        for func in [prepare_followup, start_followup]:
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username')"
            )


class TestSchedulerRoutesSessionAccess:
    """Verify scheduler helper uses session.get('username') (not decorated)."""

    def test_helper_uses_safe_get(self):
        """get_current_username is a helper, not a route — it should use .get()."""
        from local_deep_research.research_scheduler.routes import (
            get_current_username,
        )

        source = _get_function_source(get_current_username)
        assert _uses_unsafe_session_get(source), (
            "get_current_username should use session.get('username') "
            "because it is not behind @login_required"
        )


class TestBenchmarkRoutesSessionAccess:
    """Verify benchmark routes use flask_session['username']."""

    def _get_route_functions(self):
        from local_deep_research.benchmarks.web_api.benchmark_routes import (
            cancel_benchmark,
            delete_benchmark_run,
            export_benchmark_results,
            get_benchmark_history,
            get_benchmark_results,
            get_benchmark_status,
            get_running_benchmark,
            index,
            start_benchmark,
            start_benchmark_simple,
        )

        return [
            index,
            start_benchmark,
            get_running_benchmark,
            get_benchmark_status,
            cancel_benchmark,
            get_benchmark_history,
            get_benchmark_results,
            start_benchmark_simple,
            delete_benchmark_run,
            export_benchmark_results,
        ]

    def test_no_session_get_username(self):
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username')"
            )


class TestMetricsRoutesSessionAccess:
    """Verify metrics routes use flask_session['username'] (except helper functions)."""

    def _get_route_functions(self):
        from local_deep_research.web.routes.metrics_routes import (
            api_classify_domains,
            api_classification_progress,
            api_cost_analytics,
            api_enhanced_metrics,
            api_get_classifications_summary,
            api_get_domain_classifications,
            api_get_research_rating,
            api_link_analytics,
            api_metrics,
            api_rate_limiting_metrics,
            api_research_costs,
            api_research_link_metrics,
            api_save_research_rating,
            api_star_reviews,
        )

        return [
            api_metrics,
            api_rate_limiting_metrics,
            api_research_link_metrics,
            api_enhanced_metrics,
            api_get_research_rating,
            api_save_research_rating,
            api_star_reviews,
            api_research_costs,
            api_cost_analytics,
            api_link_analytics,
            api_get_domain_classifications,
            api_get_classifications_summary,
            api_classify_domains,
            api_classification_progress,
        ]

    def test_no_session_get_username_in_routes(self):
        """Decorated route functions should not use flask_session.get('username')."""
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username')"
            )

    def test_helper_functions_use_safe_get(self):
        """Helper functions (not decorated) should still use flask_session.get('username')."""
        from local_deep_research.web.routes.metrics_routes import (
            get_link_analytics,
            get_rate_limiting_analytics,
            get_rating_analytics,
            get_strategy_analytics,
        )

        for func in [
            get_rating_analytics,
            get_link_analytics,
            get_strategy_analytics,
            get_rate_limiting_analytics,
        ]:
            source = _get_function_source(func)
            assert _uses_unsafe_session_get(source), (
                f"{func.__name__} should use flask_session.get('username') "
                f"because it is not behind @login_required"
            )


class TestRAGRoutesSessionAccess:
    """Verify RAG routes use session['username'] not session.get('username')."""

    def _get_route_functions(self):
        from local_deep_research.research_library.routes.rag_routes import (
            cancel_indexing,
            configure_rag,
            create_collection,
            get_collection_documents,
            get_collections,
            get_documents,
            get_index_info,
            get_index_status,
            get_rag_stats,
            index_all,
            index_collection,
            index_document,
            remove_document,
            start_background_index,
            update_collection,
            upload_to_collection,
            view_document_chunks,
        )

        return [
            view_document_chunks,
            get_index_info,
            get_rag_stats,
            index_document,
            remove_document,
            index_all,
            configure_rag,
            get_documents,
            get_collections,
            create_collection,
            update_collection,
            upload_to_collection,
            get_collection_documents,
            index_collection,
            start_background_index,
            get_index_status,
            cancel_indexing,
        ]

    def test_no_session_get_username(self):
        """No RAG route should use session.get('username')."""
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username') "
                f"instead of session['username']"
            )


class TestDeleteRoutesSessionAccess:
    """Verify delete routes use session['username'] not session.get('username')."""

    def _get_route_functions(self):
        from local_deep_research.research_library.deletion.routes.delete_routes import (
            delete_collection,
            delete_collection_index,
            delete_document,
            delete_document_blob,
            delete_documents_blobs_bulk,
            delete_documents_bulk,
            get_bulk_deletion_preview,
            get_collection_deletion_preview,
            get_document_deletion_preview,
            remove_document_from_collection,
            remove_documents_from_collection_bulk,
        )

        return [
            delete_document,
            delete_document_blob,
            get_document_deletion_preview,
            remove_document_from_collection,
            delete_collection,
            delete_collection_index,
            get_collection_deletion_preview,
            delete_documents_bulk,
            delete_documents_blobs_bulk,
            remove_documents_from_collection_bulk,
            get_bulk_deletion_preview,
        ]

    def test_no_session_get_username(self):
        """No delete route should use session.get('username')."""
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username') "
                f"instead of session['username']"
            )


class TestNewsFlaskApiSessionAccess:
    """Verify news flask_api routes use session['username'] not session.get('username')."""

    def _get_route_functions(self):
        from local_deep_research.news.flask_api import (
            check_overdue_subscriptions,
            run_subscription_now,
            scheduler_stats,
        )

        return [
            run_subscription_now,
            scheduler_stats,
            check_overdue_subscriptions,
        ]

    def test_no_session_get_username(self):
        """No news flask_api route should use session.get('username')."""
        for func in self._get_route_functions():
            source = _get_function_source(func)
            assert not _uses_unsafe_session_get(source), (
                f"{func.__name__} uses session.get('username') "
                f"instead of session['username']"
            )
