"""Regression test for #4768.

In split-container / minimal Docker deployments the WebUI image may not ship the
agent's ``cron`` package on its import path. Before the fix, ``GET /api/crons``
(the Tasks tab's initial load) did ``from cron.jobs import list_jobs`` with no
guard, so a ``ModuleNotFoundError`` bubbled up as a 500 and broke the whole tab.

The fix degrades gracefully: an empty job list with a ``cron_unavailable`` flag.
"""
import pathlib

REPO = pathlib.Path(__file__).resolve().parent.parent
ROUTES = (REPO / "api" / "routes.py").read_text(encoding="utf-8")


def _api_crons_branch() -> str:
    """Return the source of the `if parsed.path == "/api/crons":` GET branch."""
    marker = ROUTES.index('if parsed.path == "/api/crons":')
    # Stop at the next sibling branch so we only inspect this handler.
    nxt = ROUTES.index('if parsed.path == "/api/crons/output":', marker)
    return ROUTES[marker:nxt]


def _cross_profile_helper() -> str:
    """Return the source of _cron_jobs_cross_profile."""
    marker = ROUTES.index("def _cron_jobs_cross_profile(")
    nxt = ROUTES.index("\ndef ", marker + 1)
    return ROUTES[marker:nxt]


def test_api_crons_guards_missing_cron_module():
    """The /api/crons GET branch must wrap the cron helper in a guard that
    returns a graceful payload instead of letting ModuleNotFoundError 500 — but
    only for a genuinely-absent cron package, not an internal import bug."""
    branch = _api_crons_branch()
    assert "except ModuleNotFoundError as exc" in branch, (
        "GET /api/crons must catch ModuleNotFoundError so the Tasks tab does not "
        "500 when the cron package is absent (#4768)."
    )
    # The except path returns an empty list + an unavailable flag (not a re-raise)
    # ONLY for the genuinely-missing cron package...
    assert "cron_unavailable" in branch
    assert 'exc.name in ("cron", "cron.jobs")' in branch, (
        "Must only treat an absent cron package as unavailable; an internal "
        "dependency ImportError of an existing cron/jobs.py must still surface."
    )
    # ...and re-raises everything else (a real cron bug is not swallowed).
    assert "\n            raise" in branch
    # The try in the branch guards the cron helper call.
    assert "try:" in branch


def test_api_crons_still_lists_jobs_on_happy_path():
    """The guard must not remove the normal behavior: when cron imports fine, the
    branch still calls list_jobs(include_disabled=True) under cron_profile_context."""
    helper = _cross_profile_helper()
    assert "list_jobs(include_disabled=True)" in helper
    assert "cron_profile_context_for_home" in helper
    assert "_cron_jobs_for_api(" in helper
    # The import is lazy (inside the function body, not at module level).
    assert "from cron.jobs import list_jobs" in helper
