"""
Stage vs backstage — is this notebook render stakeholder-facing?

The Mercury app (3.2.x) is a hybrid Jupyter server: the SAME server (and
kernel pool) can serve both the client-facing app view and JupyterLab, so a
server-level signal cannot tell who is looking. The reliable, per-view
signal is the session name: the app runs every session against a shadow
copy named ``<notebook>__mercury__<id>.ipynb``
(``mercury_app/handlers.py``), and the kernel sees that path in
``JPY_SESSION_NAME``. JupyterLab and nbconvert sessions carry the plain
notebook path (or no session name at all).

``MERCURY_CONFIG_DIR`` is kept as a fallback: ``mercury --working-dir …``
exports it into the server process and every kernel inherits it. It is a
server-level signal — on such a server even JupyterLab kernels carry it, so
diagnostics are then hidden in that Lab view too (hidden, never leaked; use
a separate ``jupyter lab`` for analysis, which is the normal workflow). It
is NOT set when mercury is launched without ``--working-dir``, which is why
it cannot be the primary signal.

Diagnostics routed through :func:`backstage` / :func:`backstage_md` stay
visible in JupyterLab and land in the nbconvert exports (where the
machine-readable appendix must appear for LLM consumption) but never render
in the Mercury app.
"""

from __future__ import annotations

import os
from typing import Any


def on_stage() -> bool:
    """True when this kernel renders the client-facing Mercury app view."""
    if "__mercury__" in os.getenv("JPY_SESSION_NAME", ""):
        return True                       # the app's shadow-copy session
    return os.getenv("MERCURY_CONFIG_DIR") is not None


def backstage(*args: object, **kwargs: Any) -> None:
    """``print`` that renders only backstage (JupyterLab, nbconvert)."""
    if not on_stage():
        print(*args, **kwargs)


def backstage_md(text: str) -> None:
    """Markdown that renders only backstage (JupyterLab, nbconvert).

    Emitted as a ``text/markdown`` display, so nbconvert's markdown export
    carries it verbatim — a stream ``print`` would be indented as a code
    block. Falls back to ``print`` when IPython isn't importable (plain
    pytest), where ``display`` itself already degrades to ``print``.
    """
    if on_stage():
        return
    try:
        from IPython.display import Markdown, display
    except ImportError:
        print(text)
        return
    display(Markdown(text))  # type: ignore[no-untyped-call]
