"""
Comprehensive tests for news web routes and blueprint.
Tests create_news_blueprint, page routes, and load_user_settings.
"""

from unittest.mock import patch

import pytest


class _AlwaysAuthenticated:
    def __contains__(self, key):
        return True

    def __getitem__(self, key):
        return "testuser"


@pytest.fixture(autouse=True)
def _bypass_login_required(monkeypatch):
    # These tests exercise route logic, not auth. PR #3129 added
    # @login_required to news routes; auth itself is covered in tests/web/auth/.
    monkeypatch.setattr(
        "local_deep_research.web.auth.decorators.session",
        _AlwaysAuthenticated(),
    )
    monkeypatch.setattr(
        "local_deep_research.web.auth.decorators.db_manager.is_user_connected",
        lambda *args, **kwargs: True,
    )


class TestCreateNewsBlueprint:
    """Tests for create_news_blueprint function."""

    def test_returns_blueprint(self):
        """Test returns a Flask Blueprint."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Blueprint

        bp = create_news_blueprint()
        assert isinstance(bp, Blueprint)

    def test_blueprint_has_name(self):
        """Test blueprint has correct name."""
        from local_deep_research.news.web import create_news_blueprint

        bp = create_news_blueprint()
        assert bp.name == "news"

    def test_has_deferred_functions(self):
        """Test blueprint has deferred route functions."""
        from local_deep_research.news.web import create_news_blueprint

        bp = create_news_blueprint()
        # Blueprint has routes registered via deferred functions
        assert len(bp.deferred_functions) > 0


class TestNewsPageRoute:
    """Tests for the main news page route."""

    @patch("local_deep_research.news.web.render_template")
    def test_news_page_renders_template(self, mock_render):
        """Test news_page renders correct template."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"

        app = Flask(__name__)
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/")
            mock_render.assert_called()
            call_args = mock_render.call_args
            assert "news.html" in str(call_args)

    @patch("local_deep_research.news.web.render_template")
    def test_news_page_passes_strategies(self, mock_render):
        """Test news_page passes strategies to template."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"

        app = Flask(__name__)
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/")
            call_kwargs = mock_render.call_args[1]
            assert "strategies" in call_kwargs
            assert isinstance(call_kwargs["strategies"], list)

    @patch("local_deep_research.news.web.render_template")
    def test_news_page_includes_expected_strategies(self, mock_render):
        """Test news_page includes expected default strategies."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"

        app = Flask(__name__)
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/")
            call_kwargs = mock_render.call_args[1]
            strategies = call_kwargs["strategies"]
            strategy_names = [s["name"] for s in strategies]
            # Anonymous user sees default strategies only
            assert "source-based" in strategy_names
            assert "focused-iteration" in strategy_names


class TestSubscriptionsPageRoute:
    """Tests for the subscriptions page route."""

    @patch("local_deep_research.news.web.render_template")
    def test_subscriptions_page_renders_template(self, mock_render):
        """Test subscriptions_page renders correct template."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"

        app = Flask(__name__)
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions")
            mock_render.assert_called()
            call_args = mock_render.call_args
            assert "subscriptions.html" in str(call_args)


class TestNewSubscriptionPageRoute:
    """Tests for the new subscription page route."""

    @patch("local_deep_research.news.web.render_template")
    def test_new_subscription_page_renders_template(self, mock_render):
        """Test new_subscription_page renders correct template."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"

        app = Flask(__name__)
        app.secret_key = "test"
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions/new")
            mock_render.assert_called()
            call_args = mock_render.call_args
            assert "news-subscription-form.html" in str(call_args)

    @patch("local_deep_research.news.web.render_template")
    def test_new_subscription_passes_default_settings(self, mock_render):
        """Test new_subscription_page passes default settings."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"

        app = Flask(__name__)
        app.secret_key = "test"
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions/new")
            call_kwargs = mock_render.call_args[1]
            assert "default_settings" in call_kwargs
            settings = call_kwargs["default_settings"]
            assert "iterations" in settings
            assert "search_engine" in settings

    @patch("local_deep_research.news.web.render_template")
    def test_new_subscription_passes_none_subscription(self, mock_render):
        """Test new_subscription_page passes None for subscription."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"

        app = Flask(__name__)
        app.secret_key = "test"
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions/new")
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["subscription"] is None


class TestEditSubscriptionPageRoute:
    """Tests for the edit subscription page route."""

    @patch("local_deep_research.news.web.api")
    @patch("local_deep_research.news.web.render_template")
    def test_edit_subscription_loads_subscription(self, mock_render, mock_api):
        """Test edit_subscription_page loads subscription data."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"
        mock_api.get_subscription.return_value = {
            "id": "sub-123",
            "query": "test",
        }

        app = Flask(__name__)
        app.secret_key = "test"
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions/sub-123/edit")
            mock_api.get_subscription.assert_called_once_with("sub-123")

    @patch("local_deep_research.news.web.api")
    @patch("local_deep_research.news.web.render_template")
    def test_edit_subscription_passes_subscription(self, mock_render, mock_api):
        """Test edit_subscription_page passes subscription to template."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"
        subscription = {"id": "sub-123", "query": "test"}
        mock_api.get_subscription.return_value = subscription

        app = Flask(__name__)
        app.secret_key = "test"
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions/sub-123/edit")
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["subscription"] == subscription

    @patch("local_deep_research.news.web.api")
    @patch("local_deep_research.news.web.render_template")
    def test_edit_subscription_handles_not_found(self, mock_render, mock_api):
        """Test edit_subscription_page handles subscription not found."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"
        mock_api.get_subscription.return_value = None

        app = Flask(__name__)
        app.secret_key = "test"
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions/nonexistent/edit")
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["subscription"] is None
            assert "error" in call_kwargs

    @patch("local_deep_research.news.web.api")
    @patch("local_deep_research.news.web.render_template")
    def test_edit_subscription_handles_exception(self, mock_render, mock_api):
        """Test edit_subscription_page handles exception."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        mock_render.return_value = "rendered"
        mock_api.get_subscription.side_effect = Exception("Database error")

        app = Flask(__name__)
        app.secret_key = "test"
        bp = create_news_blueprint()
        app.register_blueprint(bp, url_prefix="/news")

        with app.test_client() as client:
            client.get("/news/subscriptions/sub-123/edit")
            call_kwargs = mock_render.call_args[1]
            assert "error" in call_kwargs


class TestLoadUserSettings:
    """Tests for load_user_settings function."""

    def test_function_exists(self):
        """Test load_user_settings function exists."""
        from local_deep_research.news.web import load_user_settings

        assert callable(load_user_settings)

    def test_returns_early_without_session(self):
        """Test returns early when no db_session provided."""
        from local_deep_research.news.web import load_user_settings

        default_settings = {"iterations": 3}
        load_user_settings(default_settings, db_session=None)

        # Should not modify default_settings beyond original value
        assert default_settings["iterations"] == 3


class TestDefaultSettings:
    """Tests for default settings values."""

    def test_new_subscription_default_iterations(self):
        """Test default iterations value."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        with patch(
            "local_deep_research.news.web.render_template"
        ) as mock_render:
            mock_render.return_value = "rendered"

            app = Flask(__name__)
            app.secret_key = "test"
            bp = create_news_blueprint()
            app.register_blueprint(bp, url_prefix="/news")

            with app.test_client() as client:
                client.get("/news/subscriptions/new")
                call_kwargs = mock_render.call_args[1]
                settings = call_kwargs["default_settings"]
                assert settings["iterations"] == 3

    def test_new_subscription_default_questions_per_iteration(self):
        """Test default questions_per_iteration value."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        with patch(
            "local_deep_research.news.web.render_template"
        ) as mock_render:
            mock_render.return_value = "rendered"

            app = Flask(__name__)
            app.secret_key = "test"
            bp = create_news_blueprint()
            app.register_blueprint(bp, url_prefix="/news")

            with app.test_client() as client:
                client.get("/news/subscriptions/new")
                call_kwargs = mock_render.call_args[1]
                settings = call_kwargs["default_settings"]
                assert settings["questions_per_iteration"] == 5

    def test_new_subscription_default_search_engine(self):
        """Test default search_engine value."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        with patch(
            "local_deep_research.news.web.render_template"
        ) as mock_render:
            mock_render.return_value = "rendered"

            app = Flask(__name__)
            app.secret_key = "test"
            bp = create_news_blueprint()
            app.register_blueprint(bp, url_prefix="/news")

            with app.test_client() as client:
                client.get("/news/subscriptions/new")
                call_kwargs = mock_render.call_args[1]
                settings = call_kwargs["default_settings"]
                assert settings["search_engine"] == "searxng"

    def test_new_subscription_default_model_provider(self):
        """Test default model_provider value."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        with patch(
            "local_deep_research.news.web.render_template"
        ) as mock_render:
            mock_render.return_value = "rendered"

            app = Flask(__name__)
            app.secret_key = "test"
            bp = create_news_blueprint()
            app.register_blueprint(bp, url_prefix="/news")

            with app.test_client() as client:
                client.get("/news/subscriptions/new")
                call_kwargs = mock_render.call_args[1]
                settings = call_kwargs["default_settings"]
                assert settings["model_provider"] == "ollama"

    def test_new_subscription_default_search_strategy(self):
        """Test default search_strategy value."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        with patch(
            "local_deep_research.news.web.render_template"
        ) as mock_render:
            mock_render.return_value = "rendered"

            app = Flask(__name__)
            app.secret_key = "test"
            bp = create_news_blueprint()
            app.register_blueprint(bp, url_prefix="/news")

            with app.test_client() as client:
                client.get("/news/subscriptions/new")
                call_kwargs = mock_render.call_args[1]
                settings = call_kwargs["default_settings"]
                assert settings["search_strategy"] == "source-based"


class TestStrategyList:
    """Tests for strategy list in news page."""

    def test_strategies_include_topic_organization(self):
        """Test the strategies list includes topic-organization."""
        from local_deep_research.search_system_factory import (
            get_available_strategies,
        )

        strategies = get_available_strategies()
        strategy_names = [s["name"] for s in strategies]
        assert "topic-organization" in strategy_names

    def test_strategies_include_source_based(self):
        """Test strategies list includes source-based."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        with patch(
            "local_deep_research.news.web.render_template"
        ) as mock_render:
            mock_render.return_value = "rendered"

            app = Flask(__name__)
            bp = create_news_blueprint()
            app.register_blueprint(bp, url_prefix="/news")

            with app.test_client() as client:
                client.get("/news/")
                call_kwargs = mock_render.call_args[1]
                strategy_names = [s["name"] for s in call_kwargs["strategies"]]
                assert "source-based" in strategy_names

    def test_strategies_include_focused_iteration(self):
        """Test strategies list includes focused-iteration."""
        from local_deep_research.news.web import create_news_blueprint
        from flask import Flask

        with patch(
            "local_deep_research.news.web.render_template"
        ) as mock_render:
            mock_render.return_value = "rendered"

            app = Flask(__name__)
            bp = create_news_blueprint()
            app.register_blueprint(bp, url_prefix="/news")

            with app.test_client() as client:
                client.get("/news/")
                call_kwargs = mock_render.call_args[1]
                strategy_names = [s["name"] for s in call_kwargs["strategies"]]
                assert "focused-iteration" in strategy_names
