# TS-06 — Targeted request fails post-payment → fallback to blast
# (requirement/phase4-customer-flow.md → Test Scenarios → TS-06).
#
# §4 branch covered: Targeted → TargetedRes(reject/timeout) →
#   OfflinePopup(post-pay, returning variant) → "cari bestie lain" →
#   fallback-to-blast → §3 BlastFlow → S10.
#
# What this proves: after paying for a targeted attempt, if the picked
# mitra rejects or times out, the customer can fall back to general blast
# WITHOUT a second payment (same payment_sessions row reused).
#
# Pre-reqs (HARD):
#   - Backend reachable; NODE_ENV != 'production'.
#   - >= 2 mitras online in dev DB:
#       1. M1 — picked from history, becomes the targeted mitra; we
#          simulate them rejecting via force_pairing_timeout.js.
#       2. M2 — the blast-fallback acceptor.
#     If only one mitra is online, the fallback-to-blast cannot match.
#
# Known backend gap (TODO):
#   The current force_pairing_timeout.js endpoint calls
#   `expirePairingRequest()` which broadcasts WS PAIRING_FAILED
#   (is_terminal=false). On the TargetedWaitingScreen, this maps the
#   pairing state to PairingFailedData, NOT PairingTargetedUnavailableData
#   — so the `BestieOfflinePopup` (returning variant) won't fire from the
#   targeted-waiting screen as written.
#
#   To make this flow pass end-to-end the backend test endpoint needs to
#   detect when the latest pending_acceptance session is a TARGETED pair
#   (chat_sessions.targeted_mitra_id is set / linked to a confirmed
#   payment_session.targeted_mitra_id) and route to
#   `expireTargetedPairingRequest` instead, which broadcasts
#   RETURNING_CHAT_TIMEOUT → PairingTargetedUnavailableData → popup fires.
#
#   Until that fix lands, this flow will fail at step "OfflinePopup
#   visible". Leave it in place: it correctly expresses the intended
#   product behavior and serves as a regression test for the backend fix.
#
# Run:
#   maestro test client_app/.maestro/flows/ts-06_targeted_reject_fallback_to_blast.yaml
appId: com.mybestie
env:
  TEST_PHONE: "+6281234567890"
  BACKEND_INTERNAL_URL: http://localhost:3001
  # Second online mitra that will accept the blast fallback. See task spec
  # "Open question" — TS-06 needs >= 2 online mitras and no "any online
  # acceptor" helper exists yet.
  TEST_MITRA_ID_ACCEPTOR: "${TEST_MITRA_ID_ACCEPTOR}"
---
# --- Cold-start reset + onboarding prelude ---
- runScript:
    file: ../scripts/reset_phone.js
    env:
      TEST_PHONE: ${TEST_PHONE}
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- launchApp:
    clearState: true
- runFlow: ../subflows/onboarding_returning_user.yaml

# --- Reset every mitra online first (test idempotency). ---
- runScript:
    file: ../scripts/reset_all_mitras_online.js
    env:
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}

# --- Seed history with M1 (online — they'll be the targeted mitra). Then
# ensure a different M2 is online so the post-rejection blast has an
# acceptor. ---
- runScript:
    file: ../scripts/seed_history_session.js
    env:
      TEST_PHONE: ${TEST_PHONE}
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- runScript:
    file: ../scripts/force_other_mitra_online.js
    env:
      MITRA_ID: ${output.MITRA_ID}
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}

- swipe:
    start: "50%, 30%"
    end: "50%, 80%"
- extendedWaitUntil:
    visible:
      text: "(?s).*curhatan sebelumnya.*"
    timeout: 10000

# --- Walk TS-01 steps 1-8 to reach /chat/waiting-targeted/<mitraId> ---
- tapOn:
    text: "(?s).*curhat sama bestie baru.*"
    retryTapIfNoChange: true
- extendedWaitUntil:
    visible:
      text: "(?s).*mau curhat sama siapa.*"
    timeout: 5000
- tapOn: "(?s).*bestie yang udah kenal.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*bestie kamu sebelumnya.*"
    timeout: 5000
- tapOn: "(?s).*bestie ${output.MITRA_NAME_RE}.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*pilih cara curhat.*"
    timeout: 10000
- tapOn:
    text: "(?s).*tulis dan baca dengan tenang.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*pilih durasi.*"
    timeout: 10000
- tapOn: "(?s).*5 menit.*"
- tapOn: "(?s).*bayar Rp.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*cara bayar.*"
    timeout: 10000
- tapOn:
    text: "(?s).*bayar Rp.*"
    retryTapIfNoChange: true
- extendedWaitUntil:
    visible:
      text: "scan QRIS untuk bayar"
    timeout: 10000
- runScript:
    file: ../scripts/mark_latest_payment_paid.js
    env:
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}
- runFlow:
    when:
      visible:
        text: "(?s).*biar nggak ketinggalan.*"
    commands:
      - tapOn:
          text: "(?s).*nanti aja.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*MENUNGGU JAWABAN.*"
    timeout: 20000

# --- Force the targeted pending_acceptance session to expire ---
# TODO(backend): force-pairing-timeout currently calls
# expirePairingRequest (broadcasts PAIRING_FAILED), not
# expireTargetedPairingRequest (which would broadcast
# RETURNING_CHAT_TIMEOUT). The popup assertion below depends on the
# RETURNING_CHAT_TIMEOUT path — see header note.
- runScript:
    file: ../scripts/force_pairing_timeout.js
    env:
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}

# --- BestieOfflinePopup (returning variant, post-pay) appears ---
# Title from bestie_unavailable_dialog.dart for the `returning` variant:
# "<mitraName> lagi nggak online". Primary CTA when canFallbackToBlast is
# true (M2 is reachable + paymentSessionId is set): "chat dengan bestie
# lain". This differs from the prePayReturning variant's "cari bestie
# lain" CTA — verified in bestie_unavailable_dialog.dart L140-152.
- extendedWaitUntil:
    visible:
      text: "(?s).*${output.MITRA_NAME_RE}.*lagi nggak online.*"
    timeout: 15000
- assertVisible: "(?s).*chat dengan bestie lain.*"

# --- Tap "chat dengan bestie lain" → fallbackToBlast() ---
# In current code, fallback-to-blast creates a fresh pending request that
# may render as either /chat/searching ("lagi nyari bestie") for a
# multi-mitra blast OR /chat/waiting-targeted (MENUNGGU JAWABAN) when the
# backend reuses the existing payment session to target the next available
# mitra. Either pending state is acceptable here — the critical assertion
# is that the customer wasn't charged again (same payment_sessions row).
- tapOn: "(?s).*chat dengan bestie lain.*"
- extendedWaitUntil:
    visible:
      text: "(?s).*(lagi nyari bestie|MENUNGGU JAWABAN).*"
    timeout: 15000

# --- M2 accepts the blast (any other online mitra) ---
- runScript:
    file: ../scripts/accept_latest_pending.js
    env:
      BACKEND_INTERNAL_URL: ${BACKEND_INTERNAL_URL}

# --- Chat screen renders (with M2, not M1) ---
- extendedWaitUntil:
    visible:
      text: "(?s).*online.*"
    timeout: 20000
