"""
Tests for web/auth/middleware_optimizer.py

Tests cover:
- should_skip_database_middleware - path-based and method-based skip logic
- should_skip_queue_checks - method/path skip logic
- should_skip_session_cleanup - probabilistic skip logic
"""

import pytest
from flask import Flask
from unittest.mock import patch

from local_deep_research.web.auth.middleware_optimizer import (
    should_skip_database_middleware,
    should_skip_queue_checks,
    should_skip_session_cleanup,
)


@pytest.fixture
def app():
    """Create a minimal Flask test app."""
    app = Flask(__name__)
    app.config["TESTING"] = True
    return app


# ===================================================================
# should_skip_database_middleware
# ===================================================================
class TestShouldSkipDatabaseMiddleware:
    """Tests for should_skip_database_middleware function."""

    # -- static file paths ------------------------------------------------

    def test_skip_static_js(self, app):
        """Should skip static JS file paths."""
        with app.test_request_context("/static/js/app.js", method="GET"):
            assert should_skip_database_middleware() is True

    def test_skip_static_css(self, app):
        """Should skip static CSS file paths."""
        with app.test_request_context("/static/css/style.css", method="GET"):
            assert should_skip_database_middleware() is True

    def test_skip_static_images(self, app):
        """Should skip static image file paths."""
        with app.test_request_context("/static/images/logo.png", method="GET"):
            assert should_skip_database_middleware() is True

    def test_skip_static_nested(self, app):
        """Should skip deeply nested static paths."""
        with app.test_request_context(
            "/static/assets/vendor/lib.min.js", method="GET"
        ):
            assert should_skip_database_middleware() is True

    # -- well-known files -------------------------------------------------

    def test_skip_favicon(self, app):
        """Should skip /favicon.ico."""
        with app.test_request_context("/favicon.ico", method="GET"):
            assert should_skip_database_middleware() is True

    def test_skip_robots_txt(self, app):
        """Should skip /robots.txt."""
        with app.test_request_context("/robots.txt", method="GET"):
            assert should_skip_database_middleware() is True

    def test_skip_health(self, app):
        """Should skip /api/v1/health endpoint."""
        with app.test_request_context("/api/v1/health", method="GET"):
            assert should_skip_database_middleware() is True

    # -- Socket.IO paths --------------------------------------------------

    def test_skip_socket_io_polling(self, app):
        """Should skip Socket.IO polling paths."""
        with app.test_request_context(
            "/socket.io/?EIO=4&transport=polling", method="GET"
        ):
            assert should_skip_database_middleware() is True

    def test_skip_socket_io_websocket(self, app):
        """Should skip Socket.IO websocket paths."""
        with app.test_request_context(
            "/socket.io/?EIO=4&transport=websocket", method="GET"
        ):
            assert should_skip_database_middleware() is True

    # -- auth routes ------------------------------------------------------

    def test_skip_auth_login(self, app):
        """Should skip /auth/login."""
        with app.test_request_context("/auth/login", method="POST"):
            assert should_skip_database_middleware() is True

    def test_skip_auth_register(self, app):
        """Should skip /auth/register."""
        with app.test_request_context("/auth/register", method="POST"):
            assert should_skip_database_middleware() is True

    def test_skip_auth_logout(self, app):
        """Should skip /auth/logout."""
        with app.test_request_context("/auth/logout", method="POST"):
            assert should_skip_database_middleware() is True

    # -- OPTIONS preflight ------------------------------------------------

    def test_skip_options_preflight(self, app):
        """Should skip OPTIONS requests regardless of path."""
        with app.test_request_context("/api/research", method="OPTIONS"):
            assert should_skip_database_middleware() is True

    def test_skip_options_on_any_path(self, app):
        """Should skip OPTIONS on arbitrary paths."""
        with app.test_request_context("/settings", method="OPTIONS"):
            assert should_skip_database_middleware() is True

    # -- paths that should NOT be skipped ---------------------------------

    def test_no_skip_api_research(self, app):
        """Should NOT skip /api/research."""
        with app.test_request_context("/api/research", method="GET"):
            assert should_skip_database_middleware() is False

    def test_no_skip_api_post(self, app):
        """Should NOT skip POST to /api/research."""
        with app.test_request_context("/api/research", method="POST"):
            assert should_skip_database_middleware() is False

    def test_no_skip_settings(self, app):
        """Should NOT skip /settings."""
        with app.test_request_context("/settings", method="GET"):
            assert should_skip_database_middleware() is False

    def test_no_skip_root(self, app):
        """Should NOT skip root path /."""
        with app.test_request_context("/", method="GET"):
            assert should_skip_database_middleware() is False

    def test_no_skip_dashboard(self, app):
        """Should NOT skip /dashboard."""
        with app.test_request_context("/dashboard", method="GET"):
            assert should_skip_database_middleware() is False


# ===================================================================
# should_skip_queue_checks
# ===================================================================
class TestShouldSkipQueueChecks:
    """Tests for should_skip_queue_checks function."""

    # -- GET requests always skipped --------------------------------------

    def test_skip_get_requests(self, app):
        """GET requests should be skipped (they don't create new work)."""
        with app.test_request_context("/api/research", method="GET"):
            assert should_skip_queue_checks() is True

    def test_skip_get_on_any_path(self, app):
        """GET requests should be skipped regardless of path."""
        with app.test_request_context("/settings", method="GET"):
            assert should_skip_queue_checks() is True

    # -- inherits database middleware skip paths --------------------------

    def test_skip_static_files_post(self, app):
        """Static files are skipped even for POST."""
        with app.test_request_context("/static/js/app.js", method="POST"):
            assert should_skip_queue_checks() is True

    def test_skip_health_post(self, app):
        """Health endpoint is skipped even for POST."""
        with app.test_request_context("/api/v1/health", method="POST"):
            assert should_skip_queue_checks() is True

    def test_skip_socket_io_post(self, app):
        """Socket.IO paths are skipped even for POST."""
        with app.test_request_context(
            "/socket.io/?EIO=4&transport=polling", method="POST"
        ):
            assert should_skip_queue_checks() is True

    def test_skip_options_always(self, app):
        """OPTIONS requests are always skipped."""
        with app.test_request_context("/api/research", method="OPTIONS"):
            assert should_skip_queue_checks() is True

    # -- POST to API should NOT be skipped --------------------------------

    def test_no_skip_post_api_research(self, app):
        """POST to /api/research should NOT be skipped."""
        with app.test_request_context("/api/research", method="POST"):
            assert should_skip_queue_checks() is False

    def test_no_skip_put_requests(self, app):
        """PUT requests to non-skip paths should NOT be skipped."""
        with app.test_request_context("/api/research/123", method="PUT"):
            assert should_skip_queue_checks() is False

    def test_no_skip_delete_requests(self, app):
        """DELETE requests to non-skip paths should NOT be skipped."""
        with app.test_request_context("/api/research/123", method="DELETE"):
            assert should_skip_queue_checks() is False


# ===================================================================
# should_skip_session_cleanup
# ===================================================================
class TestShouldSkipSessionCleanup:
    """Tests for should_skip_session_cleanup function."""

    # -- probabilistic: random > 1 always skips (99%) --------------------

    def test_skip_when_random_returns_2(self, app):
        """When random returns > 1, should always skip."""
        with app.test_request_context("/api/research", method="GET"):
            with patch("random.randint", return_value=2):
                assert should_skip_session_cleanup() is True

    def test_skip_when_random_returns_50(self, app):
        """When random returns 50, should skip."""
        with app.test_request_context("/api/research", method="GET"):
            with patch("random.randint", return_value=50):
                assert should_skip_session_cleanup() is True

    def test_skip_when_random_returns_100(self, app):
        """When random returns 100, should skip."""
        with app.test_request_context("/api/research", method="GET"):
            with patch("random.randint", return_value=100):
                assert should_skip_session_cleanup() is True

    # -- probabilistic: random == 1 defers to database middleware ---------

    def test_run_cleanup_when_random_returns_1_and_normal_path(self, app):
        """When random returns 1 on a non-skip path, should NOT skip (cleanup runs)."""
        with app.test_request_context("/api/research", method="GET"):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is False

    def test_skip_static_even_when_random_returns_1(self, app):
        """Static files should skip cleanup even when random returns 1."""
        with app.test_request_context("/static/js/app.js", method="GET"):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is True

    def test_skip_health_even_when_random_returns_1(self, app):
        """Health endpoint should skip cleanup even when random returns 1."""
        with app.test_request_context("/api/v1/health", method="GET"):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is True

    def test_skip_auth_routes_even_when_random_returns_1(self, app):
        """Auth routes should skip cleanup even when random returns 1."""
        with app.test_request_context("/auth/login", method="POST"):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is True

    def test_skip_favicon_even_when_random_returns_1(self, app):
        """Favicon should skip cleanup even when random returns 1."""
        with app.test_request_context("/favicon.ico", method="GET"):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is True

    def test_skip_socket_io_even_when_random_returns_1(self, app):
        """Socket.IO paths should skip cleanup even when random returns 1."""
        with app.test_request_context(
            "/socket.io/?EIO=4&transport=polling", method="GET"
        ):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is True

    def test_skip_robots_txt_even_when_random_returns_1(self, app):
        """robots.txt should skip cleanup even when random returns 1."""
        with app.test_request_context("/robots.txt", method="GET"):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is True

    def test_skip_options_even_when_random_returns_1(self, app):
        """OPTIONS requests should skip cleanup even when random returns 1."""
        with app.test_request_context("/api/research", method="OPTIONS"):
            with patch("random.randint", return_value=1):
                assert should_skip_session_cleanup() is True
