"""
Deep behavioral tests for flask_api.py route handler logic patterns.
Tests scheduler status construction, subscription request data building,
overdue check logic, folder operations, and error handler patterns.
"""

from datetime import datetime, timezone, timedelta


# --- Scheduler status construction ---


class TestSchedulerStatusConstruction:
    """Tests for scheduler status dict building in get_scheduler_status."""

    def _build_status(self, is_running, config, user_sessions):
        """Mirror scheduler status construction from flask_api."""
        status = {
            "scheduler_available": True,
            "is_running": is_running,
            "config": config.copy() if config else {},
            "active_users": len(user_sessions),
            "total_scheduled_jobs": 0,
        }
        total_jobs = sum(
            len(session.get("scheduled_jobs", set()))
            for session in user_sessions.values()
        )
        status["total_scheduled_jobs"] = total_jobs
        status["scheduled_jobs"] = status.get("total_scheduled_jobs", 0)
        return status

    def test_scheduler_available_always_true(self):
        status = self._build_status(False, {}, {})
        assert status["scheduler_available"] is True

    def test_is_running_reflected(self):
        status = self._build_status(True, {}, {})
        assert status["is_running"] is True

    def test_config_copied(self):
        config = {"key": "val"}
        status = self._build_status(True, config, {})
        assert status["config"] == {"key": "val"}
        config["key"] = "changed"
        assert status["config"]["key"] == "val"  # copy, not reference

    def test_active_users_count(self):
        sessions = {"user1": {}, "user2": {}}
        status = self._build_status(True, {}, sessions)
        assert status["active_users"] == 2

    def test_total_scheduled_jobs(self):
        sessions = {
            "user1": {"scheduled_jobs": {"j1", "j2"}},
            "user2": {"scheduled_jobs": {"j3"}},
        }
        status = self._build_status(True, {}, sessions)
        assert status["total_scheduled_jobs"] == 3

    def test_scheduled_jobs_alias(self):
        sessions = {"user1": {"scheduled_jobs": {"j1"}}}
        status = self._build_status(True, {}, sessions)
        assert status["scheduled_jobs"] == status["total_scheduled_jobs"]

    def test_no_users(self):
        status = self._build_status(True, {}, {})
        assert status["active_users"] == 0
        assert status["total_scheduled_jobs"] == 0

    def test_empty_scheduled_jobs_set(self):
        sessions = {"user1": {"scheduled_jobs": set()}}
        status = self._build_status(True, {}, sessions)
        assert status["total_scheduled_jobs"] == 0


# --- Run subscription request data ---


class TestRunSubscriptionRequestData:
    """Tests for request_data construction in run_subscription_now."""

    def _build_request_data(self, subscription, current_date):
        query = subscription["query_or_topic"].replace(
            "YYYY-MM-DD", current_date
        )
        request_data = {
            "query": query,
            "mode": "quick",
            "model_provider": subscription.get("model_provider") or "OLLAMA",
            "model": subscription.get("model") or "llama3",
            "strategy": subscription.get("search_strategy")
            or "news_aggregation",
            "metadata": {
                "is_news_search": True,
                "search_type": "news_analysis",
                "display_in": "news_feed",
                "subscription_id": str(subscription["id"]),
                "original_query": subscription["query_or_topic"],
                "processed_query": query,
                "news_date": current_date,
                "title": subscription.get("name")
                if subscription.get("name")
                else None,
            },
        }
        if subscription.get("custom_endpoint"):
            request_data["custom_endpoint"] = subscription["custom_endpoint"]
        return request_data

    def test_replaces_date_placeholder(self):
        sub = {"id": "1", "query_or_topic": "news YYYY-MM-DD", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["query"] == "news 2025-06-15"
        assert "YYYY-MM-DD" not in data["query"]

    def test_no_placeholder(self):
        sub = {"id": "1", "query_or_topic": "AI news", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["query"] == "AI news"

    def test_mode_always_quick(self):
        sub = {"id": "1", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["mode"] == "quick"

    def test_model_provider_default(self):
        sub = {"id": "1", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["model_provider"] == "OLLAMA"

    def test_model_provider_override(self):
        sub = {
            "id": "1",
            "query_or_topic": "test",
            "model_provider": "openai",
            "name": None,
        }
        data = self._build_request_data(sub, "2025-06-15")
        assert data["model_provider"] == "openai"

    def test_model_default(self):
        sub = {"id": "1", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["model"] == "llama3"

    def test_strategy_default(self):
        sub = {"id": "1", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["strategy"] == "news_aggregation"

    def test_metadata_has_subscription_id(self):
        sub = {"id": "sub-42", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["metadata"]["subscription_id"] == "sub-42"

    def test_metadata_is_news_search(self):
        sub = {"id": "1", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["metadata"]["is_news_search"] is True

    def test_metadata_stores_original_query(self):
        sub = {"id": "1", "query_or_topic": "AI YYYY-MM-DD", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["metadata"]["original_query"] == "AI YYYY-MM-DD"
        assert data["metadata"]["processed_query"] == "AI 2025-06-15"

    def test_title_from_name(self):
        sub = {"id": "1", "query_or_topic": "test", "name": "My Sub"}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["metadata"]["title"] == "My Sub"

    def test_title_none_when_no_name(self):
        sub = {"id": "1", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert data["metadata"]["title"] is None

    def test_custom_endpoint_added(self):
        sub = {
            "id": "1",
            "query_or_topic": "test",
            "name": None,
            "custom_endpoint": "http://custom",
        }
        data = self._build_request_data(sub, "2025-06-15")
        assert data["custom_endpoint"] == "http://custom"

    def test_no_custom_endpoint(self):
        sub = {"id": "1", "query_or_topic": "test", "name": None}
        data = self._build_request_data(sub, "2025-06-15")
        assert "custom_endpoint" not in data


# --- Overdue check patterns ---


class TestOverdueCheckPatterns:
    """Tests for overdue subscription detection logic."""

    def test_overdue_when_next_refresh_past(self):
        now = datetime.now(timezone.utc)
        next_refresh = now - timedelta(hours=1)
        is_overdue = next_refresh <= now
        assert is_overdue is True

    def test_not_overdue_when_future(self):
        now = datetime.now(timezone.utc)
        next_refresh = now + timedelta(hours=1)
        is_overdue = next_refresh <= now
        assert is_overdue is False

    def test_overdue_when_exactly_now(self):
        now = datetime.now(timezone.utc)
        is_overdue = now <= now
        assert is_overdue is True

    def test_only_active_checked(self):
        status = "paused"
        should_check = status == "active"
        assert should_check is False

    def test_active_checked(self):
        status = "active"
        should_check = status == "active"
        assert should_check is True

    def test_update_after_run(self):
        now = datetime.now(timezone.utc)
        interval = 60
        new_next = now + timedelta(minutes=interval)
        assert new_next > now


# --- APScheduler job list formatting ---


class TestAPSchedulerJobFormatting:
    """Tests for APScheduler job list formatting."""

    def _format_job(self, job_id, job_name, next_run_time):
        return {
            "id": job_id,
            "name": job_name,
            "next_run": next_run_time.isoformat() if next_run_time else None,
        }

    def test_with_next_run(self):
        dt = datetime(2025, 6, 15, 12, 0, 0, tzinfo=timezone.utc)
        job = self._format_job("j1", "check_sub_1", dt)
        assert job["next_run"] is not None
        assert "2025-06-15" in job["next_run"]

    def test_without_next_run(self):
        job = self._format_job("j1", "check_sub_1", None)
        assert job["next_run"] is None

    def test_job_id_preserved(self):
        dt = datetime(2025, 6, 15, tzinfo=timezone.utc)
        job = self._format_job("my-job-id", "name", dt)
        assert job["id"] == "my-job-id"

    def test_limit_to_10_jobs(self):
        jobs = list(range(20))
        limited = jobs[:10]
        assert len(limited) == 10


# --- Error handler patterns ---


class TestErrorHandlerPatterns:
    """Tests for error handler response patterns."""

    def test_400_error_format(self):
        response = {"error": "Bad request"}
        assert response["error"] == "Bad request"

    def test_404_error_format(self):
        response = {"error": "Resource not found"}
        assert response["error"] == "Resource not found"

    def test_500_error_format(self):
        response = {"error": "Internal server error"}
        assert response["error"] == "Internal server error"


# --- Folder validation ---


class TestFolderValidation:
    """Tests for folder validation patterns."""

    def test_name_required(self):
        data = {}
        is_valid = bool(data.get("name"))
        assert is_valid is False

    def test_empty_name_invalid(self):
        data = {"name": ""}
        is_valid = bool(data.get("name"))
        assert is_valid is False

    def test_name_present_valid(self):
        data = {"name": "My Folder"}
        is_valid = bool(data.get("name"))
        assert is_valid is True

    def test_folder_already_exists_409(self):
        existing = {"name": "My Folder"}
        is_duplicate = existing is not None
        assert is_duplicate is True

    def test_folder_not_found_404(self):
        folder = None
        not_found = not folder
        assert not_found is True


# --- Subscription filter by date ---


class TestSubscriptionFilterByDate:
    """Tests for subscription ID filtering via LIKE pattern."""

    def test_like_pattern_format(self):
        sub_id = "sub-123"
        pattern = f'%"subscription_id":"{sub_id}"%'
        assert f'"subscription_id":"{sub_id}"' in pattern

    def test_all_subscription_skip(self):
        subscription_id = "all"
        should_filter = subscription_id and subscription_id != "all"
        assert should_filter is False

    def test_none_subscription_skip(self):
        subscription_id = None
        should_filter = subscription_id and subscription_id != "all"
        assert not should_filter

    def test_specific_subscription_filter(self):
        subscription_id = "sub-abc"
        should_filter = subscription_id and subscription_id != "all"
        assert should_filter is True


# --- User session debug info format ---


class TestUserSessionDebugFormat:
    """Tests for scheduler stats debug info formatting."""

    def _format_session_info(self, session_info, has_credential=False):
        return {
            "has_password": has_credential,
            "last_activity": session_info.get("last_activity").isoformat()
            if session_info.get("last_activity")
            else None,
            "scheduled_jobs_count": len(
                session_info.get("scheduled_jobs", set())
            ),
        }

    def test_has_password_true(self):
        info = self._format_session_info({}, has_credential=True)
        assert info["has_password"] is True

    def test_has_password_false(self):
        info = self._format_session_info({}, has_credential=False)
        assert info["has_password"] is False

    def test_last_activity_formatted(self):
        dt = datetime(2025, 6, 15, 12, 0, 0, tzinfo=timezone.utc)
        info = self._format_session_info({"last_activity": dt})
        assert "2025-06-15" in info["last_activity"]

    def test_last_activity_none(self):
        info = self._format_session_info({})
        assert info["last_activity"] is None

    def test_scheduled_jobs_count(self):
        info = self._format_session_info({"scheduled_jobs": {"j1", "j2", "j3"}})
        assert info["scheduled_jobs_count"] == 3

    def test_empty_scheduled_jobs(self):
        info = self._format_session_info({})
        assert info["scheduled_jobs_count"] == 0
