
    `gj,                   0    d Z ddlmZ ddlZ G d d      Zy)u  Billing and subscription handlers for the interactive CLI (god-file decomposition).

This module hosts the Nous billing/subscription methods lifted out of
``cli.py``'s ``HermesCLI`` class. ``HermesCLI`` inherits
``CLIBillingMixin`` so every ``self.<handler>`` call resolves unchanged
via the MRO — behavior-neutral apart from focused billing fixes.

Import discipline mirrors ``hermes_cli.cli_commands_mixin``:
  * Neutral, non-cyclic dependencies are imported at module top level below.
  * cli.py-internal symbols (the ``_cprint``/``_b``/``_d`` helpers and
    display constants) are imported LAZILY inside each method via
    ``from cli import ...``. The mixin never imports ``cli`` at module load
    time, avoiding the cycle created when ``cli.py`` imports this mixin.
    )annotationsNc                      e Zd ZdZd(dZd)dZd Zd ZdddZd	 Z	d
 Z
dddZd Zd*dddZdddZd Zd Zd+d,dZddd-dZd Zd.dZd Zd(dZd Zd Zd Zd  Zd! Zd" Zddd#d$Zd% Zd& Zd' Z y)/CLIBillingMixinz@Mixin holding interactive-CLI billing and subscription handlers.c                D   ddl m}m}m} 	 ddlm}m}  |       }|@|j                  r3|0d}|j                  xs |j                  dk(  rdnd}t        |dd      xs  ||j                        }	|	rd	|	 nd
}
|r"t                 |d |d| |
               d}| j                  ||j                        D ]  } ||       d} |j                  r"|j                    |d|j                   d       |j                  dk(  r |d |d              d}n@|j                  dk(  r1|j                   d|j                   dnd}d| d} |d|        d}|ryddlm}  |       }|syt                |D ]  }t        d|         y# t        $ r d}d}Y w xY w)u  Print the Nous dollar balance block (two-bar view) when a Nous account
        is logged in. Returns True if it printed anything.

        Prefers the shared dollar usage model (``agent.billing_usage`` — two-bar
        plan/top-up view, dollars-only, the /usage + /subscription source of
        truth). Falls back to the legacy ``nous_credits_lines`` text only when the
        model is unavailable. Agent-independent (a portal fetch gated on "a Nous
        account is logged in"), so /usage shows the block even in the TUI
        slash-worker subprocess that resumes WITHOUT a live agent. Fail-open and
        wall-clock-bounded; honors HERMES_DEV_CREDITS_FIXTURE for offline testing.
        r   _cprint_b_d)build_usage_modelformat_renewsNFfreeFreerenews_display    · renews    Plan: T  Total spendable: $,.2fuC   > Free · free models only. Run /subscription to reach paid models.low$under $5   ! Low balance · z# left. Run /topup or /subscription.)nous_credits_lines)clir   r	   r
   agent.billing_usager   r   	Exception	available	plan_namestatusgetattr	renews_atprint_usage_bar_lines	has_topuptotal_spendable_usdagent.account_usager   )selfr   r	   r
   r   r   usageprinted_anyplanr   renews_bar_ln_amt_lowr   lineslines                    O/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/cli_billing_mixin.py_print_nous_credits_blockz)CLIBillingMixin._print_nous_credits_block   s    	('	!L%'E
 ]5NK??R1GvTD$U,<dCe}UZUdUdGeN7E{>"232F"R&vh 789:;"  00H # "# 5#<#<#H.u/H/H.NOP||v%"R efghi"&?D?X?X?d544T:;jt*4&0ST"TF$" 	;"$ 	DBtf+	[  	!E M	!s   F FFc                6    ddl m}m}  |d |d              y)aE  Print the `/usage` call-to-action pointing at /subscription + /topup.

        Mirrors the TUI's ``USAGE_CTA`` (``session.ts``) so every surface ends a
        usage read with the same nudge. Only called when a Nous account is logged
        in (the balance block printed), since both commands are Nous-account only.
        r   r   r
   r   uA   Run /subscription to change plan · /topup to add to your balanceN)r   r   r
   )r(   r   r
   s      r2   _print_usage_ctaz CLIBillingMixin._print_usage_ctaY   s     	$"R[\]^_    c                   ddl m}m}m} ddlm}m}  |       }|j                  sRt                |j                  r |d |d|j                                 y |d |d              t        d       y|j                  d	k(  rt                 |d
 |d              t        dd        |j                  rG|j                  xs dj                         }d|j                   |rd| nd } |d ||              |j                  xs d}	t        d|	 d       t        d        |d |d              y| j                  | ||             y)u  `/subscription` (alias `/upgrade`) — view the Nous plan + browser hand-off.

        The CLI mirror of the TUI ``SubscriptionOverlay``: a read of the current
        plan, this cycle's subscription credits, renewal date, and the plans you
        could switch to — then a deep-link to NAS's own ``/manage-subscription``
        page (NOT the Stripe portal; that page routes upgrade→Checkout /
        downgrade→scheduled internally). The terminal NEVER charges for a
        subscription. Fail-open: logged-out / portal hiccup degrades to a clear
        message, never a crash. Mirrors ``_show_billing``
        discipline for the interactive-vs-text split.
        r   r   )build_subscription_statesubscription_manage_url     💳 zCould not load subscription: Not logged into Nous Portal.z4  Run `hermes portal` to log in, then /subscription.Nteam     ⚕ zTeam subscriptionr   {   ─────────────────────────────────────────r   Org:     · z
a team orgz   This terminal is connected to z. Teams run on a sharedu%     balance · use /topup to add funds.z5Personal subscriptions live on your personal account.)r   r   r	   r
   agent.subscription_viewr9   r:   	logged_inr#   errorcontextorg_nameroletitle_subscription_overview)
r(   r   r	   r
   r9   r:   staterG   	_org_lineorgs
             r2   _show_subscriptionz"CLIBillingMixin._show_subscriptionh   sT    	('](*G{{'"'DU[[M%R"S!TUV  '"%C"D!EFGLM ==F"GfR 34567Bzl#$~~

(b//1#ENN#3Td4&Mr3RS	"R	]O,-..0LC4SE9PQR9:bSTUVW##E+B5+IJr7   c                   ddl m}m}m} ddlm} 	 ddlm}  |       }|j                  }	|	xr |	j                   }
|j                  }|	r|	j                  xs |	j                  n|r|j                  nd}|rt        |dd      nd}| }|rt        |dd      nd}|s |	r|	j                  r ||	j                        }d}|	r|	j                  rd	}n|	r|	j                   rd
|	j                    }|sd}nc|-|dk(  r(|j"                  d|j"                  d}d| | d| d}n4|rt        |dd      nd}|d|ddnd}|rdn|rd| nd}d| | | | }d}|	r6|	j                  r* ||	j$                        xs d}|	j                  xs dd|f}nA|	r?|	j                   r3 ||	j&                        xs d}|	j                  xs d|	j                   |f} |d       |rN|\  }}} |d |d               |d| d| d |d|z                  |d |d| d                |d        |d! ||              t)        dd"        | j+                  ||      D ]  }t)        |        |r3t        |d#d$      r&t        |dd      t)        d%|j"                  d       |
r |d |d&              n6|dk(  r1||j"                  d|j"                  dnd'}d(| d)} |d|        |j,                  rG|j.                  xs dj1                         }d*|j,                   |rd| nd } |d ||              t)        dd"        |s,t)                 |d |d+              |rt)        d,|        yt        | d-d      s&t)                |rt)        d.|        t)        d/       y|
r| j3                  ||d01       y| j5                  ||       y# t        $ r d}Y w xY w)2u  Print the plan read block, then the browser hand-off to manage it.

        Dollars-only (no "credits") — mirrors the TUI overlay: a status line, the
        shared two-bar dollar usage view (plan + top-up) with the plan name on
        the bar, and state-matched free/low nudges. No in-terminal tier picker —
        the only action is managing the subscription on the portal.
        r   r   r   r   Nr    r   r   u    → cancelsu    → u   Plan: Free · free models onlyr   r   r   r   rA   z leftr&   u    · $u    · view onlyr   the end of the billing period	your plancancelszthe end of the cycleu     ⏳ zScheduled changer   u    ──▶ u   · z	You keep z (and its credits) until then.r>   r?   r%   Fr   z;> Paid models need a subscription. Start one to reach them.r   r   z1 left. Top up or upgrade before a mid-run cutoff.r@   z%Plan changes need an org admin/owner.  Manage on portal: _appz  Manage your subscription: z5  Open it in your browser, then re-run /subscription.zStart a subscriptionverb)r   r   r	   r
   r   r   r   r   currenttier_idcan_change_plan	tier_namer   r!   cycle_ends_atcancel_at_period_endpending_downgrade_tier_namer&   cancellation_effective_atpending_downgrade_atr#   r$   rF   rG   rH   _subscription_open_portal_subscription_change_menu)r(   rJ   
manage_urlr   r	   r
   r   r   r)   cis_free
can_changer   u_status	view_onlyr   _flipr    _tot_spend_left_tail_trans_when_from_tor-   r.   r/   rG   rK   s                                  r2   rI   z&CLIBillingMixin._subscription_overview   sk    	(' 	6	=%'E MMQYY'**
23Q[[-AIIU%//X\	5:75(D1"N	CH(8$?d!*1??;N ''"E100A99:;E5F8u#49R9R9^u0067Di[tD6?FDIWU$94@tF282DeF4=."E'0OYg^DT7UmoEi[wug>F
 ''!!"="=>aBaE{{1kIuEF100!!"8"89S=SE{{1kA4Q4QSXYF &E3fR 23456b{3%r"UU]2C1DEFbiw.LMNOPQBK&F%&:,  ,,UI> 	G'N	WUK7GEK`bf<g<s()B)B4(HIJ bYZ[\];@;LQVQjQjQvQu0067  }GD&tf,]^DbK >>JJ$"++-D/$tf2/NOIbI():, 
 GbCDEFG,ZL9:tVT*G4ZLABMN**5*CY*Z 	&&uj9C  	E	s   O O! O!Manage your subscriptionrV   c                  ddl m}m} |st                 |d |d              yt                d|dfdd	g}| j	                  |d
|      }| j                  ||      }|dk(  r>d}		 ddl}
|
j                  |      }	|	st        d|        t                t        d       y|dk(  r!	 | j                  |       t        d|        yt        d       y# t        $ r d}	Y ew xY w# t        $ r t        d|        Y yw xY w)u@   Open / copy the manage-subscription URL — the portal hand-off.r   r5   r   u6   No manage URL available — is your portal configured?Nopenz*open the subscription page in your browser)copyz	Copy linkz2copy the manage-subscription URL to your clipboardcancelCancel
do nothingr   rH   detailchoicesF  Open this URL: z4  Finish in your browser, then re-run /subscription.ru   u     📋 Copied: z  Manage URL:      🟡 Cancelled.)
r   r   r
   r#   _prompt_text_input_modal_normalize_slash_confirm_choice
webbrowserrt   r   _write_osc52_clipboard)r(   rJ   rc   rW   r   r
   r|   rawchoiceopenedr   s              r2   ra   z)CLIBillingMixin._subscription_open_portal  s   #GbTUVWXTGHW.

 ++$r7+S55c7CVF!#4 )*67GHIv5++J7
|45 %&    5zl345s$   'C (C% C"!C"%C?>C?c                   |j                   }t        |xr |j                  xs |j                        }|r|j                  ndxs d}|rdd| ddfdg}nddg}|j                  d	       |j                  d
       | j                  dd|      }| j                  ||      }|dk(  r| j                  |       y|dk(  r| j                  |d       y|dk(  r| j                  |       y|dk(  r| j                  ||       yt        d       y)zAThe in-terminal change menu for a paid admin/owner (interactive).NrR   keepzKeep z (undo the scheduled change)zcancel the pending change)changeChange planz$upgrade or downgrade in the terminal)
cancel_subCancel subscription#schedule cancellation at period endportalManage on portalz%open the billing page in your browser)closeClosery   rr   r   rz   r   )resumeNr   r   u     🟡 Closed. No plan change.)rX   boolr]   r^   r[   appendr   r   _subscription_pick_tier_subscription_apply_subscription_confirm_cancelra   r#   )	r(   rJ   rc   rd   has_pending	keep_namer|   r   r   s	            r2   rb   z)CLIBillingMixin._subscription_change_menu,  s   MM1Z!"8"8"YA<Y<Y[$%Q[[4?K	
 5+GHJefQG R\G 	^_78++2LUWah+i55c7CX((/v$$U,<=|#--e4x**5*=23r7   c           	        ddl m} |j                  }t        |j                  xs d      }t        d |D        d      }t        |D cg c]2  }|j                  s|j                  r|j                  xs ddkD  s1|4 c}d       }|st        d       yg }|D ]f  }|j                  xs d|kD  rd	nd
}	|j                  |j                  |j                   d ||j                         d|	 d|j                   f       h |j                  d       | j                  dd|r|j                   nd d|      }
| j#                  |
|      }|r|dk(  rt        d       y| j%                  ||       yc c}w )uD   Tier picker → preview → confirm (mirrors the TUI picker screen).r   format_money c              3  N   K   | ]  }|j                   s|j                    y wN)
is_current
tier_order).0ts     r2   	<genexpr>z:CLIBillingMixin._subscription_pick_tier.<locals>.<genexpr>T  s     F1!,,Fs   %%c                "    | j                   xs dS )Nr   )r   )r   s    r2   <lambda>z9CLIBillingMixin._subscription_pick_tier.<locals>.<lambda>Y  s    !,,+! r7   )keyz6  No other plans are available to switch to right now.Nupgrade	downgraderA   u   /mo · z
switch to rw   Backry   r   z	Current: r   z$. Pick a plan to preview the effect.rz   rw   !     🟡 Cancelled. No plan change.)agent.billing_viewr   rX   tupletiersnextsorted
is_enabledr   r   r#   r   rY   namedollars_per_monthr   r[   r   !_subscription_preview_and_confirm)r(   rJ   r   rd   r   	cur_orderr   
selectabler|   	directionr   r   s               r2   r   z'CLIBillingMixin._subscription_pick_tierN  s   3MMekk'R(FFJ	 _1allHYXY]^G^Q_+

 JK 	EA&'ll&7a9%D	+INNAII!&&l1CVCV6W5XX_`i_j'koyz{  {A  {A  zB  nC  D  E	E 	78++aq{{V<<`a , 

 55c7C8+56..uf=) `s   E3E3'E3;E3Tallow_stepupc                  ddl m}m}m} ddlm} ddlm}m}	m	}
  |d |d              	  |
|      } ||      }|j                  }|j                  xs d}t                |dk(  r |d |d| d              y|dvr8ddlm}  |d|j                   xs d         ||      }|rt        d|        y|dk(  r|j"                  d|j"                  dz  dnd} |d |d       d |d              |r |d| d| d       n |d| d       d}	 dd lm}  |d!"      }|j(                  r|j*                  nd}||j,                  d#v r|j.                   d$} |d ||              |rd%| d&nd'}d(|f}d)d*|d+fg}nn|j2                  r't5        |j2                        d,k\  r|j2                  dd, nd-} |d |d       d |d.               |d/| d0| d1       d2| }d3|f}d*|d4fd5g}|j6                  r |d |d6|j6                   d7              | j9                  |d8|9      }| j;                  ||      d*k7  rt        d:       y| j=                  |||;       y# |	$ r' |r| j                  |d|f	       Y yt        d
       Y y|$ r}| j                  ||       Y d}~yd}~ww xY w# t0        $ r Y dw xY w)<a
  Preview the change (chargeless quote), show the effect, then confirm+apply.

        ``allow_stepup=False`` (a post-grant replay) declines a second step-up on a
        repeated scope denial so the flow can't re-prompt/re-open the browser in a
        loop.
        r   r   )(subscription_change_preview_from_payload)BillingErrorBillingScopeRequiredpost_subscription_previewr   u   Checking the change…subscription_type_idpreview)retry\     Terminal billing still isn't enabled for this org — enable it on the portal, then retry.Nzthe selected planno_opzYou are already on u    — nothing to change.)
charge_now	scheduled)r:        🟡 uA   This change cannot be confirmed here — manage it on the portal.rT   r   r   d   z.2fzConfirm plan changeu   · charged nowz  Upgrade to z. You will be charged z now (prorated).z.. You will be charged the prorated amount now.z.The card on your subscription will be charged.build_billing_stateg      @)timeout)subPincustomerDefaultu7    — the card on your subscription — will be charged.Pay z & upgrade nowzUpgrade now (prorated charge)r   rw   Go backdo not chargeyeszcharge + upgrade now
   rQ      · scheduled · not todayz  Change to u    — takes effect z7. No charge now; you keep your current plan until then.zSchedule change to schedulezapply this change)rw   r   zdo not changezMonthly credits change: .r   rz   r   r   )r   r   r	   r
   rB   r   hermes_cli.nous_billingr   r   r   #_subscription_handle_scope_requiredr#   _subscription_render_erroreffecttarget_tier_namer:   reasonamount_due_now_centsr   r   rC   cardresolved_viamaskedr   effective_atlenmonthly_credits_deltar   r   r   )r(   rJ   rY   r   r   r	   r
   r   r   r   r   payloadexcpr   targetr:   _mur.   
_card_liner   _bs_c	pay_labelactionconfirm_choicesro   r   s                               r2   r   z1CLIBillingMixin._subscription_preview_and_confirmn  sr    	('Tii"R01234
	/WMG 5W=##:':Wb1&9PQRSTU44 Hgahhm*mnop)%0C,SE23\!=>=S=S=_Qq--3C89eiDb1232b9I6J5KLM-x/EdVK[\]-x/]^_
 JJB)#6!$SXXD>boo9V&V$&II;.e!fJ bJ()*7;$tfN3A`I)F 7	#9:O
 -.NNs1>>?RVX?XANN3B'_~Eb1232b9T6U5VWXl6(*<UGCz{|-fX6I '*F	#676O ""b6q7N7N6OqQRSTU++)BP_+`//_EN56  \ JS $ 	88yRYFZ8[  tu 	++E37	P  s6   	I. AJ< .J9J9J9J44J9<	K	K	c                   ddl m}m}m} ddlm} |j                  }|r|j                  r ||j                        ndxs d}t                 |d |d       d |d               |d	|r|j                  nd
 d| d        |d |d              ddg}| j                  dd|      }	| j                  |	|      dk7  rt        d       y| j                  |d       y)z4Confirm, then schedule a cancellation at period end.r   r   rO   NrQ   r   zConfirm cancellationr   z	  Cancel rR   u    — it stays active until z, then won't renew.zOYou keep your remaining credits for this period. You can resume before it ends.)r   r   r   )rw   r   zkeep your planzCancel subscription?r   rz   r   u)     🟡 Cancelled. Your plan is unchanged.)rw   N)r   r   r	   r
   r   r   rX   r\   r#   r[   r   r   r   )
r(   rJ   r   r	   r
   r   rd   _endr   r   s
             r2   r   z,CLIBillingMixin._subscription_confirm_cancel  s    ''5MM34aoo.twXw"R./026Q3R2STU)AQ[[;@@[\`[aatuv"RijklmQ3
 ++2HQS]l+m//_EN=>  (89r7   Nc               j   ddl m}m}m}m} ddlm}	m}
m}m	}m
}m}m}m} |\  }}d}|dk(  rddlm} |xs  |       }	 |dk(  r	  |||      xs i }|j'                  d      }|j'                  d      xs d}|j'                  d      }|dk(  r |d| d| d|        y|dk(  r |d| d| d|        y|dk(  r |d       |r |d|        y|dk(  r |d       |r |d|        y| j%                  d       y|dk(  r ||        |d| d|        n7|dk(  r |d         |d| d!|        n|d"k(  r |         |d| d#|         |d |d$              y# |$ r  |
||f$ r}| j!                  ||       Y d}~yd}~w|	$ rS}t#        |dd      }t#        |d	d      }|d
v s||dk\  r| j%                  |       n| j!                  ||       Y d}~yd}~ww xY w# |$ r& |r| j)                  |||%       Y yt+        d&       Y y|	$ r}| j!                  ||       Y d}~yd}~ww xY w)'a  Run the mutation for `action`, handling the scope step-up + the result.

        `action` is one of ("upgrade", tier_id) / ("schedule", tier_id) /
        ("cancel", None) / ("resume", None). insufficient_scope routes to the
        step-up and replays; the upgrade idempotency key is reused across the replay.
        ``allow_stepup=False`` (a post-grant replay) declines a second step-up on a
        repeated scope denial so the flow can't re-prompt/re-open the browser in a loop.
        r   r   r
   _DIM_RST)r   BillingTransientBillingRemoteSpendingRevokedr   BillingSessionRevoked"delete_subscription_pending_changepost_subscription_upgradeput_subscription_pending_changeNr   new_idempotency_key)r   idempotency_keyr    rD   )network_errorendpoint_unavailablei  targetTierNamezyour new planrecoveryUrlalready_on_tierr   u   ✓ You are already on r   upgradedu   ✓ Upgraded to z,. Your new monthly credits land in a moment.requires_actionuL     🟡 This upgrade needs extra verification (3DS). Finish it on the portal.
  Portal: payment_faileduV     🔴 Your card was declined. Update your payment method on the portal and try again.r   r   ut   ✓ Scheduled — your plan doesn't change today. You keep it until the end of the billing period, then it switches.rw   T)rw   uu   ✓ Scheduled — your plan stays active until the end of the billing period, then it cancels. Nothing changes today.r   u-   ✓ Undone — you stay on your current plan.z*Re-run /subscription anytime to review it.)r   r   r   )r   r   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r!   &_subscription_render_upgrade_ambiguousgetr   r#   )r(   rJ   r   r   r   r   r
   r   r   r   r   r   r   r   r   r   r   kindargr   r   resr   _status_coder    r   _urls                               r2   r   z#CLIBillingMixin._subscription_apply  s    	0/		
 		
 		
 	c9>!:%8%:C=	8y 3^abhfhC. *ww/0COww}-..b&=dV1TFKL  z)b&6tf<himhnop  00jk*TF 34  //tu*TF 34  ??Ez!/SI"TF  #W  X\  W]  ^  _!/t<"TF  #X  Y]  X^  _  `!24"TF"OPTvVWbHIJKLe , (*?A]^  33E3?# %c8T:G#C$7E IIW_`gkn`n
 CCCH 77sCV $ 	v88f^a8btu 	8++E377	8s   G( E& AG( !G( 8G( G( .G(  A%G( &G%3F
G( 
G%A	G G(  G%%G( (H2H2H2H--H2)r   c                  ddl m}m}m}m} t                t        d        |d |d              t        | dd      st        d       yd	d
g}| j                  dd|      }	| j                  |	|      dk7  rt        d       yt        d       	 ddl	m
}
  |
d      }|st        d       y |d| d|        	 ddlm} |j                          ddlm} 	  |       }|\  }}|dk(  r| j#                  ||d       y| j%                  |||d       y# t        $ r}t        d|        Y d}~yd}~ww xY w# t        $ r Y rw xY w# t        $ r |}Y uw xY w)u@  insufficient_scope → grant terminal billing (step-up), then replay `retry`.

        Mirrors _billing_handle_scope_required: the classic CLI calls
        step_up_nous_billing_scope directly (it opens the browser + blocks), then
        replays the held preview/mutation so the user never re-runs the command.
        r   r     ! One-time setupr   zTo change your plan from the terminal, enable terminal billing once. It opens your browser to authorize, then your change picks up right here.rU   NzM  Run `hermes portal` and enable terminal billing, then re-run /subscription.r   Enable terminal billingzopen your browser to authorizenozNot nowrw   r  .Opens your browser to authorize this terminal.rz   r   z<  No change made. Enable terminal billing when you're ready.4     Opening your browser to enable terminal billing…step_up_nous_billing_scopeTopen_browser$  Couldn't enable terminal billing: u\     Couldn't enable terminal billing — an org admin or owner has to approve it for this org.u   ✓ Terminal billing enabled.)nous_billing)r9   r   Fr   )r   r   )r   r   r
   r   r   r#   r!   r   r   hermes_cli.authr  r   
hermes_clir  invalidate_cached_tokenrB   r9   r   r   )r(   rJ   r   r   r   r
   r   r   r   r   r  grantedr   _nbr9   freshrkindrargs                     r2   r   z3CLIBillingMixin._subscription_handle_scope_required9  s    	0/"#"R  i  j  k  l  	mtVT*abP'
 +++C# , 

 //_ENPQDE	B0dCG pq"TF7v>?
	6'')
 	E	,.E tI225$U2S$$UE?af$g;  	8>?	  		  	E	s<   D =D: E	 	D7D22D7:	EE	EEc                    ddl m} t        |dd      }t        |      xs d}|dk(  r	 |d       n|dv r |d	|        n |d
|        t        |dd      }|r |d|        yy)zLRender a subscription BillingError (a lighter _billing_render_charge_error).r   )r   rD   NzSomething went wrong.insufficient_scopeu=     🟡 Terminal billing isn't enabled. Enable it, then retry.)subscription_mutation_rejectedpreview_rejectedr        🔴 
portal_urlr  )r   r   r!   str)r(   rJ   r   r   codemsgr  s          r2   r   z*CLIBillingMixin._subscription_render_errorx  s~    sGT*#h11''STKKgcUO$gcUO$sL$/j'( r7   c                    ddl m}m}  |d        |d |d              |t        |dd      nd}|r |d|        yy)	ue  A charge-route failure (transport / timeout / 500 / unknown status) is
        AMBIGUOUS — NAS may have already prorated + charged. Steer to a re-check,
        never a flat failure that invites a blind retry (mirrors the TUI's
        upgradeResult(null) — the CLI can't persist the key across a command re-run,
        so a re-check is the safe path).r   r5   uS     🟡 Couldn't confirm the upgrade — your card may or may not have been charged.r   z<Re-run /subscription to check your plan before trying again.Nr+  r  )r   r   r
   r!   )r(   r   r   r
   r  s        r2   r  z6CLIBillingMixin._subscription_render_upgrade_ambiguous  sQ     	$ef"RVWXYZ36?wsL$/j'( r7   c                   ddl m}m} ddlm}  |       }|j
                  sTt                |j                  r!d|j                   } |d ||              y |d |d              t        d       y| j                  |       y)	u  `/topup` — terminal billing for Nous (one interactive modal).

        ZERO sub-commands: any argument is ignored. Bare ``/topup`` always
        opens the Overview (Screen 1), whose numbered menu is the *only* way to
        reach the Buy / Auto-reload / Monthly-limit sub-screens. (Per the unified
        UX spec §0.4 — ``/topup buy`` etc. are gone; we don't error on a stray
        arg, we just open the menu.)

        Interactive CLI uses the prompt_toolkit modal; non-interactive contexts
        (TUI slash-worker / no live app) render text + the portal deep-link, never
        prompting (the URL is the affordance), same discipline as ``_show_subscription``.
        All money is Decimal end-to-end; the terminal never collects card details.
        r   r5   r   zCouldn't load billing: r;   r<   z-  Run `hermes portal` to log in, then /topup.N)	r   r   r
   r   r   rC   r#   rD   _billing_overview)r(   commandr   r
   r   rJ   _msgs          r2   _show_billingzCLIBillingMixin._show_billing  s     	$:#%G{{0>'"T(,-  '"%C"D!EFGEF 	u%r7   r   r   c               `    t        |dd      }|sy|rt        d|        t        d|        y)zCPrint a portal deep-link line (the funnel for portal-only actions).r+  Nr   rT   )r!   r#   )r(   rJ   r   urls       r2   _billing_portal_hintz$CLIBillingMixin._billing_portal_hint  s7    e\40Bvh- $SE*+r7   c           	     v   ddl m}m}m} ddlm} 	 ddlm}  |       }t                 |d |d ||j                                       |j                  rG|j                  xs dj                         }d	|j                   |rd
| nd }	 |d ||	              t        dd        | j                  |t        |dd            D ]  }
t        |
        |j                   }|I|j"                  r2t        d ||j$                         d ||j&                                nt        d       |j(                  rL|j*                  r@|j,                  #t        d|j,                  j.                          n |d |d              t        dd        |j(                  s# |d |d              | j1                  |       y|j*                  s% |d |d              | j1                  |d       yt        | dd      s| j1                  |       yg d}| j3                  dd|      }| j5                  ||      }|dk(  r| j7                  |       y|dk(  r| j9                  |       y|dk(  r| j;                  |       y|dk(  r| j=                  |       yt        d       y# t        $ r d}Y w xY w) u  Screen 1 — overview: balance in title, two-bar dollar usage, action menu.

        Dollars-only (no "credits") — mirrors the TUI /topup overlay: balance
        leads in the title, the shared plan + top-up bars render below, then the
        reordered menu (Add funds first). No scope preflight — terminal billing
        is discovered reactively when a charge 403s insufficient_scope.
        r   r   r   rP   Nr;   u   Top up · balance r   r@   rA   r   r?   r   u     Auto-reload: on — below     → reload to z  Auto-reload: offz  Card: uG   No saved card on file — “Add funds” walks you through adding one.+Billing actions require an org admin/owner.,Terminal billing is turned off for this org.z*Enable it on the portal to add funds here.r5  rU   ))buy	Add fundszadd money to your balance)autoAuto-reloadzconfigure automatic top-ups)limitzMonthly limitz&show the monthly spend cap (read-only)r   rv   zTop up your balancerz   r=  r?  rA  r   z  Cancelled.)r   r   r	   r
   r   r   r   r   r   r#   balance_usdrF   rG   rH   r$   r!   auto_reloadenabledthreshold_usdreload_to_usdrZ   cli_billing_enabledr   displayr8  r   r   _billing_buy_flow_billing_auto_reload_flow_billing_limit_screen_billing_open_portal)r(   rJ   r   r	   r
   r   r   r)   rG   rK   r-   arr|   r   r   s                  r2   r1  z!CLIBillingMixin._billing_overview  s    	('3	=%'E 	'"1,u?P?P2Q1RSTUVW>>JJ$"++-D/$tf2/NOIbI():,  ,,UGE;PT4UV 	G'N	 >zz2<@P@P3Q2R S%%1"2B2B%C$DF
 *+   U%>%>zz%!3!3 456"R ijklm:,  $$bIJKLM%%e,((bJKLMN%%e4`%a tVT*%%e,
 ++' , 
 55c7CU?""5)v**51w&&u-x%%e,.!i  	E	s   J) )J87J8c                F   g }|rt        |dd      nd}||j                  dkD  rt        dt        dt	        |j
                  dz                    }d|z  dd|z
  z  z   }|j                  d|j                   dnd	}|xs d
j                  d      dd }|j                  d| d| d|j                  dd|j                  d| 	       |rt        |dd      nd}	|	D|	j                  dkD  r5|j                  ddj                  d       dd d|	j                  dd       |S )u  The plan + top-up dollar bars as ready-to-print lines (filled = remaining).

        Returns [] when there's nothing to draw. The caller resolves ``plan_name``
        (the plan-bar label) and picks its own print fn — block ordering differs
        per surface (``_cprint`` vs ``print`` under patch_stdout). One source of
        truth for the bar format across /usage, /subscription, and /topup.
        plan_barNr   r   u   █u   ░rA   z% usedr   r+      r   [z]  $r   z
 left of $	topup_barztop-upu   ██████████u    · never expires)
r!   	total_usdmaxminroundfill_fractionpct_usedljustr   remaining_usd)
r(   r)   r   r0   pbfilledbarpct_slabeltbs
             r2   r$   z CLIBillingMixin._usage_bar_lines+  s<    16WUJ-D>bllQ.CE"*:*:R*?$@ABF6>erF{&;<C24++2Id2;;-v.rE(&//22A6ELL2eWAcU$r/?/?.EZPRP\P\]aObchbijk27WUK.T>b..2LL2hnnQ/0*T"BRBRSWAXXijkr7   c                    t        |dd       }|st        d       y d}	 dd l}|j                  |      }|st        d|        t        d       y # t        $ r d}Y )w xY w)Nr+  z  No portal URL available.Fr   r}   z*  Complete billing changes in the browser.)r!   r#   r   rt   r   )r(   rJ   r7  r   r   s        r2   rL  z$CLIBillingMixin._billing_open_portal@  sn    e\40./	__S)F %cU+,:;	  	F	s   A AAc                    ddl m}m} |j                  s-t	                 |d |d              | j                  |       y|j                  s/t	                 |d |d              | j                  |d       yy	)
zGGuard charge/auto-reload entry points; print + return False if blocked.r   r5   r;   r;  Fr<  zEnable it on the portal first.r5  T)r   r   r
   rZ   r#   r8  rG  )r(   rJ   r   r
   s       r2   _billing_require_adminz&CLIBillingMixin._billing_require_adminP  sx    #$$Ggb!NOPQR%%e,((Ggb!OPQRS%%e4T%Ur7   c           	     N   ddl m}m}m}m}m} t                 |d |d               |d        |d |d              g d}t        d	      D ]  }| j                  d
d|      }	| j                  |	|      }
|
dk(  r#| j                  |        |d |d              Q|
dk(  r_ddlm} 	  |       }||j                  r|}|j                  ) |d| d|j                  j                    d|        |c S t        d        n t        d       y# t        $ r d}Y mw xY w)u  No saved card → guide adding one on the portal, with a re-check loop.

        Cards are added on the portal (never in-terminal). "I've added it" re-fetches
        billing state so the purchase continues right here once the card is saved —
        this also recovers a transient miss (the card display is best-effort
        server-side). Returns the refreshed state (card present), or None to abandon.
        r   )r   r	   r
   r   r   r;   zAdd a card firstz  No saved card on file.r   ua   Add a card once on the portal billing page — after that you can top up right from the terminal.))r   zAdd a card on the portalz&opens the billing page in your browser)rechecku   I've added it — check againz"re-check for the card and continuer   rP  z
Add a cardr   rz   r   uC   Add the card on the billing page, then pick “check again” here.re  r   Nu   ✓ Card found: u    — continuing.uM     Still no card on file — finish adding it on the portal, then check again.  Cancelled. No funds added.)r   r   r	   r
   r   r   r#   ranger   r   rL  r   r   r   rC   r   rH  )r(   rJ   r   r	   r
   r   r   r|   _r   r   r   r#  s                r2   _billing_add_card_flowz&CLIBillingMixin._billing_add_card_flow`  sP    	43'"/0123*+"R{|}~

 q 	A//l2W^/_C99#wGF!))%0"R efghi"B!/1E $!E::)b&6uzz7I7I6JJZ[_Z`ab Lef+	, 	,- ! ! E!s   /DD$#D$c                X   ddl m}m} ddlmm} | j                  |      syt        | dd      sjdj                  fd|j                  D              }t                 |d |d	              t        d
|        t        d       | j                  |       y|j                   | j                  |      }||j                  yg }|j                  D ]%  }|j                  t        |       |      df       ' |j                  d       |j                  d       |j                  }|rd|j                    nd}	| j#                  d	|	|      }
| j%                  |
|      }|r|dk(  rt        d       yddlm} |dk(  rt| j+                  d      }|t        d       y ||xs d|j,                  |j.                        }|j0                  st        d|j2                          y|j4                  }n		  ||      }| j9                  ||       y# t6        $ r t        d       Y yw xY w)u@   Screen 2 (preset select) → Screen 3 (confirm + charge + poll).r   )r   r	   r   validate_charge_amountNrU   z, c              3  .   K   | ]  } |        y wr   r   )r   r   r   s     r2   r   z4CLIBillingMixin._billing_buy_flow.<locals>.<genexpr>  s     NAQNs   r;   r>  z  Presets: z9  Run this in the interactive CLI to complete a purchase.zone-time credit purchase)customu   Custom amount…zenter your own amountrv   z	Payment: zNo saved card on filerz   rw   rf  )Decimalrn  z  Amount (USD): r   min_usdmax_usdr*  u     🔴 Invalid selection.)r   r   r	   r   r   rl  rc  r!   joincharge_presetsr#   r8  r   ri  r   r,  rH  r   r   decimalro  _prompt_text_inputrq  rr  okrD   amountr   _billing_confirm_and_charge)r(   rJ   r   r	   rl  presetspreset_choicesr   r   r{   r   r   ro  enteredvrx  r   s                   @r2   rI  z!CLIBillingMixin._billing_buy_flow  s   #K**51 tVT*iiN9M9MNNGGgbo./0Ky)*MN%%e,
 :://6E}

 2%% 	YA!!3q6<?<V"WX	YUV@Azz/39T\\N+9P++fn , 
 55c>J8+01#X--.@AG45&2u}}emmA 44y)*XXF 
 	((7	  12s   7H H)(H)c                   ddl m}m}m} ddlm}m} |j                  }t                 |d |d              t        dd        t        d ||              |r5t        d	|j                          |j                   |d |d              t        dd        d}	 |d ||	              dd ||       ddfddg}
t        | dd
      st        d       y
| j                  d ||       d|r|j                  nd|
      }| j                  ||
      }|dk(  r| j                  |       y
|dk7  rt        d       y
ddlm}m}m}  |       }	  |||      }|j+                  d      }|st        d       y
 |d |d              | j-                  |||       y
# |$ r | j'                  |||       Y y
|$ r}| j)                  ||       Y d
}~y
d
}~ww xY w) uF   Screen 3 — confirm total + consent, charge, then poll to settlement.r   r   )r   r   r;   zConfirm purchaser   r?   z	  Total: z  Payment: Nz.Your card saved on the portal will be charged.z;By confirming, you allow Nous Research to charge your card.payr   z nowzsubmit the charge)r   r   z)manage your card / billing in the browserr   rU   z3  Run in the interactive CLI to confirm a purchase.?zno saved cardrz   r   rf  )r   r   post_charge
amount_usdr   rx  r   chargeIdu6     🔴 No charge id returned; please check the portal.u-   Charge submitted — confirming settlement…)r   r   r	   r
   r   r   r   r   r#   rH  
provenancer!   r   r   rL  r   r   r   r  _billing_handle_scope_required_billing_render_charge_errorr	  _billing_poll_charge)r(   rJ   rx  r   r	   r
   r   r   r   _consentr   r   r   r   r   r  r   resultr   	charge_ids                       r2   ry  z+CLIBillingMixin._billing_confirm_and_charge  s#   ''Hzz'"/0123:, 	,v./01K~./ &"R PQRST:, I 	 	"R\N#$ d</057JKW2

 tVT*GH++f-.a0$(DLLo# , 

 55c?KX%%e,U?01	
 	
 "#		 FCHF JJz*	JK"RGHIJK!!%F; $ 	 //fVY/Z 	--eS9	s   
F% %G  G GG c                   ddl }ddlm} ddlm}m}m} |j                         dz   }	d}
|j                         |	k  r	  ||      }|j                  d
      }|dk(  r?|j                  d      }ddlm} |r | ||            n ||      }t        d| d       y|dk(  r"| j                  ||j                  d             y|j                  |
       |j                         |	k  rt        d       | j                  |       y# |$ r6}|j                  xs d}|j                  t        |d             Y d}~d}~w|$ r}t        d	|        Y d}~yd}~ww xY w)zGPoll loop: 2s interval, 5-min cap, cancellable. settled = ledger truth.r   Nr   )r   r   get_charge_statusi,  g       @      u#     🔴 Could not check the charge: r    settled	amountUsd)parse_moneyu     ✓ z added to your balance.failedr   us     🟡 Still processing after 5 minutes — this is a timeout, not a failure. Check /billing or the portal shortly.)timer   r   r   r   r   r  retry_aftersleeprU  r#   r	  r  _billing_render_charge_failedr8  )r(   rJ   r  rx  _timer   r   r   r  deadlineintervalr    r   wait	state_stramtr  showns                     r2   r  z$CLIBillingMixin._billing_poll_charge  sL   3	
 	
 ::<#%jjlX%	*95 

8,II%jj-::=[%56<PVCWug%<=>H$225&**X:NOKK!1 jjlX%6 	 ? 	@!!%(5 $ +!CbM* ;C5ABs#   D E	+D::EEEc                    |xs dj                         }|dk(  rt        d       n5|dk(  rt        d       n$|dk(  rt        d       nt        d|xs d	 d
       | j                  |       y)zCBranch the poll `failed` reasons to the right copy + portal funnel.r   authentication_requiredu`     🔴 Your bank requires verification (3DS). Complete it on the portal to finish this purchase.payment_method_expiredu6     🔴 Your card has expired. Update it on the portal.card_declinedu>     🔴 Your card was declined. Try another card on the portal.u%     🔴 The charge didn't go through (processing_errorz).N)stripr#   r8  )r(   rJ   r   s      r2   r  z-CLIBillingMixin._billing_render_charge_failedG  su    ,B%%'.. 4 5//JK&RS9&:VDV9WWYZ[!!%(r7   c                2   ddl m}m}m} t	        |dd      }t	        |dd      }t	        |dd      xs t	        |dd      }t        ||      s|dk(  r|dk(  rd	nd
}	t        d|	 d       nt        ||      s|dk(  rt        d       n|dk(  rt        d       n|dv st	        |dd      dk(  rt        d       n|dk(  rt        d       n|dk(  rt        d       n|dk(  r>t	        |di       xs i j                  d      }
|
t        d|
 d       ntt        d       nht        ||      r=t	        |dd      }|rd t        d!t        |d"z               d#nd$}t        d%| d&       n|d'k(  rt        d(       nt        d|        |rt        d)|        yy)*z6Render a typed BillingError at submit time (pre-poll).r   )r   r   r   rD   Nactorr+  remote_spending_revokedadminz*An admin stopped this terminal's spending.z%You stopped this terminal's spending.r*  u>    Reconnect to restore — run `hermes portal` to re-authorize.session_revokeduH     🔴 Your session was logged out. Run `hermes portal` to log in again.no_payment_methoduC     💳 No card on file — top up and manage billing on the portal.)cli_billing_disabledremote_spending_disabledr-  r  uU     Terminal billing is off for this account — an admin must enable it on the portal.role_requiredzO  Adding funds needs an org admin/owner. Ask an admin, or manage on the portal.idempotency_conflictuU     🔴 That charge key was already used for a different amount. Start a fresh top-up.monthly_cap_exceededr   remainingUsdu&     🔴 Monthly spend cap reached — $z headroom left.u!     🔴 Monthly spend cap reached.r  z (try again in ~   <   z min)r   u!     🟡 Too many charges right nowz. This isn't a payment failure.r'  uO     🔴 Terminal billing needs approval — run /topup to enable it, then retry.r  )
r   r   r   r   r!   
isinstancer#   r	  rT  rV  )r(   rJ   r   r   r   r   r-  r  r+  who	remainingr  minss                r2   r  z,CLIBillingMixin._billing_render_charge_errorU  s   	
 	
 sGT*Wd+S,5[VZ9[
c78DD]<] w& @?  GC5 ^_`23t?P7P\]((WXIIVT*.HHij_$cd++ij++ i4:??OI$>ykYZ9:-.3t4DIM%c!U4"9-=&>%?uESUD5dV;Z[\)) cdGC5/"Jzl+, r7   r  c                  ddl m}m} ddlm} | ||      nd}t                t        d        |d |d| d	              t        | d
d      st        d       yddg}| j                  dd|      }	| j                  |	|      }
|
dk7  rt        d       yt        d       	 ddl	m
}  |d      }|st        d       yddlm}  |       }|j                  r|j                  st        d       | j                  |       y|j                   .t        d        |d |d              | j                  |       y|t        d       yt        d       dd  ||       d!d"fd#g}| j                  d$ ||       d%|      }	| j                  |	|      dk7  rt        d&       ydd'lm}m} dd(lm} |xs  |       }	  |||)      }|j-                  d*      }|st        d+       y |d |d,              | j/                  |||       y# t        $ r}t        d|        Y d}~yd}~ww xY w# |$ r}| j+                  ||       Y d}~yd}~ww xY w)-u  403 insufficient_scope → in-flight reauth, then resume the held charge.

        The buy path discovers terminal billing isn't enabled only when the
        charge 403s — there is no preflight. We enable it in-flight ("Enable
        terminal billing" → browser device-flow), then on return ask the user to
        press Enter to resume the held ``amount`` (reusing ``idempotency_key`` so
        the resumed charge collapses with the original). Never leaks the raw
        billing:manage scope.
        r   r5   r   Nzyour top-upr  r   z`To charge this terminal, enable terminal billing once. It opens your browser to authorize, then z picks up right here.rU   z>  Run `hermes portal` and enable terminal billing, then retry.r  r  r  r  rz   r   zF  No charge made. Run /topup when you want to enable terminal billing.r  r  Tr  r  uj     Couldn't enable terminal billing — an org admin or owner has to approve it. Your card was not charged.r   z  Terminal billing was enabled for this terminal, but it's still turned off for this org. Enable it in the portal, then run /topup again.uC     ✓ Terminal billing enabled — but there's no card on file yet.z4Top up and manage billing on the portal to continue.u7     ✓ Terminal billing enabled. Run /topup to continue.u     ✓ Terminal billing enabled.r   zResume z top-upzfinish the held purchase)rw   rx   r   zResume your top-upu.    is ready to finish — press Enter to resume.rf  )r   r  r   r  r  z1  No charge id returned; please check the portal.u1   Resuming your top-up — confirming settlement…)r   r   r
   r   r   r#   r!   r   r   r  r  r   r   rC   rG  r8  r   r   r   r  r   r  r	  r  )r(   rJ   rx  r   r   r
   r   
amount_strr   r   r   r  r!  r   r   r#  resume_choicesr   r  r   r   r  r  s                          r2   r  z.CLIBillingMixin._billing_handle_scope_required  s    	$3-3-?\&)]
"#"Rz  |F  {G  G\  ]  ^  _  `  	atVT*RSP'
 +++C# , 

 55c?KU?Z[DE	B0dCG ~
 	;#%E$=$=  ^  _%%e,
 ::WXbRSTUV%%e, >KL 	/0f!5 6g>@Z[1
 ++&"6*++YZ" , 

 //^DP01 	F:6!4!6	 FCHF JJz*	EF"RKLMNO!!%F;E  	8>?	t  	--eS9	s0   %H  
H2 	H/H**H/2I7IIc           	        ddl m}m}m} ddlm}m} | j                  |      sy|j                  }|j                  }t        |xr |j                        }	t                 |d |d              t        dd         |d |d	              |rt        d
|j                          nt        d       | j                  |       y|	r1t        d ||j                         d ||j                                 t#        | dd      st        d       | j                  |       y|	rxg d}
| j%                  dd ||j                         d ||j                          |
      }| j'                  ||
      }|dk(  r| j)                  |       y|dk7  rt        d       y|	r ||j                        nd}d}||rd| dndz  }| j+                  |      }|t        d       y|xs dj-                         s|	r|j                  }n` ||xs d|j.                  |j0                        }|j2                  r|j4                  t        d|j6                          y|j4                  }|	r ||j                         nd}d}||rd| dndz  }| j+                  |      }|t        d       y|xs dj-                         s|	r|j                   }n` ||xs d|j.                  |j0                        }|j2                  r|j4                  t        d|j6                          y|j4                  }||||k  rt        d       yt                d|j                   d  ||       d!} |d ||              d"d#g}| j%                  d$d% ||       d ||       |      }| j'                  ||      }|d&k7  rt        d       ydd'lm}m}m} 	  |d(tA        |      tA        |      )       t        d* ||       d ||       d+       y# |$ r | jC                  |       Y y|$ r}| jE                  ||       Y d}~yd}~ww xY w),u7  Screen 4 — auto-reload config: threshold + reload-to → PATCH.

        Prefills the current values from ``state.auto_reload``. Validates both
        amounts (2dp, within bounds, ``reload_to > threshold``). When auto-reload
        is already on, offers a "Turn off" path (PATCH ``enabled:false``).
        r   r   rk  Nr;   r@  r   r?   z1Automatically add funds when your balance is low.z  Card on file: u1     No saved card — manage billing on the portal.z  Currently: below r:  rU   z6  Run in the interactive CLI to configure auto-reload.))editzEdit thresholdsz change when / how much to reload)offzTurn offzdisable auto-reloadrv   u   On — below rz   r  r  r~   z   When balance falls below (USD)z [z]: z: r   rp  r*  z  Reload balance to (USD)u;     🔴 Reload-to amount must be greater than the threshold.z5By confirming, you authorize Nous Research to charge z whenever your balance reaches z*. Turn off any time here or on the portal.)agreezAgree and turn onzenable auto-reloadrv   zTurn on auto-reload?zBelow r  r   r   patch_auto_top_upTrD  	thresholdtop_up_amountu     ✅ Auto-reload on: below r   )#r   r   r	   r
   r   r   rl  rc  r   rC  r   rD  r#   r   r8  rE  rF  r!   r   r   _billing_auto_reload_disablerv  r  rq  rr  rw  rx  rD   r   r   r   r  floatr  r  )r(   rJ   r   r	   r
   r   rl  r   rM  currently_ontop_choicesr   topcur_thr
thr_promptthreshold_rawthreshold_amttvcur_rel
rel_prompt
reload_raw
reload_amtrv_ar_consentr   r   r   r   r  r   s                                 r2   rJ  z)CLIBillingMixin._billing_auto_reload_flow  s    	('K**51zzB-2::.'"]+,-.:, "RKLMNO$T[[M23EF%%e,%l23C3C&D%E F)"*:*:;<>
 tVT*JK%%e, K
 //##L1A1A$B#C D!!-b.>.>!? @B $ 0 C 66sKHCe|11%8f})* 5A,r//0d7
77)3'<
//
; %&#**,,,M'#U]]EMMB 55BII-z*+IIM 5A,r//0d0
77)3'<
,,Z8
%& b'')l))J' b%--B 55BII-z*+J!6*:UOPCDKK= Q--9--H,I J78 	
 	"R_%&'@.
 ++(L78U_H`Gab# , 

 55c?KW%&	
 	
		m(<ER\L] 	,\--H,I J'
34A7 	8 $ 	//6 	--eS9	s   P
 
Q"Q&P==Qc                h   ddl m}m}m} |j                  }|r!|j
                  t        |j
                        nd}|r!|j                  t        |j                        nd}	  |d||       t        d       y# |$ r | j                  |       Y y|$ r}| j                  ||       Y d}~yd}~ww xY w)zTurn off auto-reload (PATCH ``enabled:false``).

        The endpoint requires ``threshold``/``topUpAmount`` in the body even when
        disabling, so we echo back the current values (falling back to 0).
        r   r  Ng        Fr  u     ✅ Auto-reload turned off.)r   r   r   r  rC  rE  r  rF  r  r  r#   )	r(   rJ   r   r   r  rM  thrrelr   s	            r2   r  z,CLIBillingMixin._billing_auto_reload_disable  s    	
 	
 )+0@0@0LeB$$%RU)+0@0@0LeB$$%RU	es#N 	-. $ 	//6 	--eS9	s   "A9 9B1B1B,,B1c                   ddl m}m}m} ddlm} t                 |d |d              t        dd        |j                  }||j                   |d |d	              nH ||j                        } ||j                        }|j                  rd
nd}	t        d| d| d|	        d}
 |d ||
              | j                  |       y)uA   Screen 5 — monthly spend limit (read-only; cap is portal-only).r   r   r   r;   zMonthly spend limitr   r?   Nz/No monthly cap visible (managed on the portal).z (default ceiling)r   z of z used this monthuK   The monthly limit is set on the portal — the terminal shows it read-only.)r   r   r	   r
   r   r   r#   monthly_cap	limit_usdspent_this_month_usdis_default_ceilingr8  )r(   rJ   r   r	   r
   r   capspentrA  ceiling_limit_notes              r2   rK  z%CLIBillingMixin._billing_limit_screen  s    ''3'"23456:, ;#--/bMNOPQ !9!9:E /E.1.D.D*"GBugT%(8	BC 	 	"R_%&'!!%(r7   )returnr   )r  Noner   )z/topup)r2  r,  )r   r,  r  r  )r  list)!__name__
__module____qualname____doc__r3   r6   rM   rI   ra   rb   r   r   r   r   r   r   r  r4  r8  r1  r$   rL  rc  ri  rI  ry  r  r  r  r  rJ  r  rK  r   r7   r2   r   r      s    J?B	`*KXq:f D^ #'J 4D>@ QU XKt:,Y8W[ Y8v TX =h~)")$&@ <> ,e"N*<  *XG8RD<L*)X)--^ ?CTX i<VO8b/2)r7   r   )r  
__future__r   r  r   r   r7   r2   <module>r     s    # Z) Z)r7   