from recoil.core.model_profiles import get_model

# JT-validated fallback for primary-model refusal (Pre-flight probe 2026-06-17).
# NB2 = is2i-gemini-3.1-flash-image (NOT the inpainting-only nano-banana-2 variant).
BOARD_FALLBACK_MODEL = "gemini-3.1-flash-image-preview"   # recoil model id;
                                                          # flora id is2i-gemini-3.1-flash-image

# Refusal/422 signals in run_result.error that trigger the single fallback retry.
_REFUSAL_SIGNALS = ("422", "refus", "content")


def select_board_model(*, beat, primitive, override: str | None = None) -> str:
    """Resolve the PRIMARY board model. Precedence:
      1. explicit override param (the A/B seam) — return it verbatim.
      2. beat-level board_model on beat.beat_metadata, if present.
      3. config default get_model('storyboard', 'image') -> gpt-image-2 (REC-182).
    Inputs are the REAL in-scope objects at both board_builder sites (beat, primitive).
    NO CLI flag (no board CLI entry point exists — see scope note)."""
    if override:
        return override
    meta = (getattr(beat, "beat_metadata", None) or {})
    bm = meta.get("board_model")
    if isinstance(bm, str) and bm:
        return bm
    return get_model("storyboard", "image")


def board_fallback_model(primary: str) -> str:
    """The model to retry on a primary-model content-refusal/422. Pinned to the
    JT-validated NB2 fallback. If primary IS already the fallback, returns it —
    the caller treats a second refusal as a hard block, not infinite fallback."""
    return BOARD_FALLBACK_MODEL


def is_board_refusal(run_result) -> bool:
    """True iff a board dispatch RunResult is a refusal/422-style failure (the
    live failure surface: run_result.success is False with a refusal signal in
    run_result.error), NOT a generic failure. No raised exception involved."""
    if run_result is None or getattr(run_result, "success", True):
        return False
    err = (getattr(run_result, "error", "") or "").lower()
    return any(sig in err for sig in _REFUSAL_SIGNALS)
