/**
 * Subscription + billing tools — ADR-210 Phase 2, extended by the MPP pay
 * rail (spec 2026-08-24 WS-B).
 *
 * Three MCP tools that surface the explicit billing read + action layer
 * complementing the ambient `_meta.session_state.billing_slice` shipped
 * in Phase 1:
 *
 *   - pica_subscription_status (read; readOnlyHint=true)
 *       Wraps `GET /api/admin/subscription` and flattens it into the card
 *       below (`SubscriptionStatusFlat`), composing a templated `summary`
 *       line the agent uses verbatim. It is no longer the 9 fields ADR-210
 *       § Phase 2 specified: two trial fields came off on 2026-08-21, and
 *       WS-B added `pricing` + `held`, each present only when the route
 *       measured it. Read the interface, not a count.
 *
 *   - pica_subscription_manage (action; readOnlyHint=false)
 *       Single-verb dispatcher over the existing
 *       `POST /api/admin/subscription` (subscribe / upgrade) and
 *       `POST /api/admin/subscription/portal` (manage / cancel) routes.
 *       Returns a `resource_link` content block (universal MCP floor)
 *       and uses `elicitation/create url` only when the client
 *       advertises `capabilities.elicitation.url` per ADR-200 Phase 1
 *       (capability-gated; `feedback_mcp_sdk_capability_gates_elicitation.md`).
 *
 *   - pica_billing_pay (read; readOnlyHint=true)
 *       Wraps `POST /api/admin/billing/pay-link`. Mints a link for one
 *       offer — resident_month / unlock / settle — and never charges: an
 *       agent POSTs the link with a Machine Payments credential, or a
 *       person opens it and pays by card. The refusals the ROUTE itself
 *       composes — billing disabled, nothing held, offer moved — come back
 *       as structured results rather than thrown ApiErrors. A 4xx from the
 *       auth wrapper in front of it is quoted, never re-interpreted; a 4xx
 *       carrying nothing quotable, and everything from 500 up, is re-thrown
 *       (`payRefusal` below is the single place that decides which).
 *
 * No new Stripe SDK calls — every route here is reused as-is.
 */
import { ApiError, PicaClient, type BillingTier, type HeldSummary, type PayOffer, type PricingSummary, type SubscriptionStatusResponse } from "@withpica/mcp-sdk";
import { ToolDefinition, ToolExecutor, ToolResult } from "./index.js";
/**
 * ⚠️ ADR-276 REMOVED THE TRIAL AND THE TIER LADDER. This tool described both to
 * agents until 2026-08-21.
 *
 * `billing_state` is the STORED value and keeps its three legacy names because
 * that is what `organisations.billing_state` holds — renaming it here would make
 * the wire disagree with the database. `plan` is the same fact in the vocabulary
 * that is actually true, and it is what an agent should say out loud:
 *
 *   billing_state  plan            what it means under ADR-276
 *   ────────────── ─────────────── ──────────────────────────────────────────
 *   trial          free_runway     walked in, never charged. no clock, no card.
 *   active         resident        paying one flat fee per 30-day cycle
 *   hibernated     paused          a cycle lapsed; deep-processing is off
 *
 * `trial_days_remaining` and `trial_ends_at` are GONE. They were null for 100%
 * of production organisations (`billing_trial_ends_at` is NULL on all 241), so
 * removing them drops two fields that could only ever say "null" — the cheapest
 * possible moment to take a concept off the wire. Codes for arguments, labels
 * for prose (`.claude/rules/canonical-model.md`).
 */
interface SubscriptionStatusFlat {
    billing_state: "trial" | "active" | "hibernated";
    plan: "free_runway" | "resident" | "paused";
    current_tier: BillingTier | null;
    capacity_used: number;
    capacity_limit: number | null;
    capacity_pct: number;
    recommended_tier: BillingTier | null;
    summary: string;
    /**
     * The org's price card and what is being withheld. Both are OMITTED rather
     * than set to null when the route has none — `null` on a flat card reads to
     * an agent as "pica measured this and the answer is nothing", which for a
     * price would mean free. Absence says "pica did not answer", which is true.
     */
    pricing?: PricingSummary;
    held?: HeldSummary;
}
/** The stored billing state in the vocabulary ADR-276 actually uses. */
export declare function planFor(billingState: "trial" | "active" | "hibernated"): "free_runway" | "resident" | "paused";
/**
 * Compose `SubscriptionStatusFlat` from the GET admin route's shape: eight
 * fields that are always present (`billing_state`, `plan`, `current_tier`,
 * `capacity_used`, `capacity_limit`, `capacity_pct`, `recommended_tier`,
 * `summary`) plus `pricing` and `held`, each emitted ONLY when the route
 * measured it.
 *
 * ⚠️ This opened by quoting a FIELD COUNT until 2026-08-26, and that count had
 * been wrong since 08-21 — `trial_days_remaining` and `trial_ends_at` came off
 * then, and WS-B added the two optional keys. A count is the one thing a
 * docstring cannot keep true across a field change, and it rots silently
 * because nothing compiles against it. Do not reintroduce one: name the fields
 * (above) or point at the interface, which the compiler keeps honest.
 *
 * Mirrors `getOrgBillingSlice`'s "no meaningful cap" rule for `capacity_pct`
 * (0 whenever current_tier is null OR enterprise) and carries through
 * `overflow.recommendedTier` (already `inferTierFromCount`-derived) per
 * Stage 1 Q2.
 *
 * Exported for unit tests.
 */
export declare function flattenStatus(status: SubscriptionStatusResponse): SubscriptionStatusFlat;
/**
 * The price half of the summary, built ENTIRELY from the figures the route
 * sent. No amount of money appears here on purpose: the money is worded once,
 * by the pay-link route's offer labels (`formatMoney` over the org's own
 * currency, whose minor-unit conventions differ from ICU's for four of the
 * ten supported currencies). A second wording here would be a second home for
 * the price — the defect FIX_LOG 2026-08-20 records as having had ten.
 *
 * Returns `null` when there is nothing measured to say, so the caller appends
 * nothing rather than a sentence about absence.
 *
 * Exported for unit tests.
 */
export declare function composePriceLine(pricing?: PricingSummary, held?: HeldSummary): string | null;
/**
 * The sentence an agent says out loud. Server-side template (Stage 1 Q1 option
 * A) so wording does not vary across connectors.
 *
 * ⚠️ REWRITTEN 2026-08-21. Every branch was false under ADR-276:
 *
 *   trial      → "You're on a 9-day window of your trial. Today's catalogue
 *                 fits the solo tier."   — there is no trial and no tier ladder
 *   hibernated → "Your trial has ended and the catalogue is read-only.
 *                 Subscribe to restore writes."
 *                 — hibernation gates `pica_audio_analyze` and nothing else;
 *                   the catalogue is NOT read-only, and there is nothing to
 *                   subscribe to
 *   active     → "Currently on pro. 412 of 4,000 slots used."
 *                 — the capacity ladder was superseded
 *
 * 239 of 241 production organisations sit at `billing_state = 'trial'`, so the
 * first branch was what an agent said to almost every user pica has. The screen
 * had already been corrected; this had not, which is the recurring shape here —
 * see `.claude/rules/canonical-model.md` on `WORK_NO_WRITER`.
 *
 * Capacity is deliberately not mentioned: no cap is enforced under ADR-276, and
 * quoting a limit implies one. The work count is stated as a plain fact instead.
 *
 * Exported for unit tests.
 */
export declare function composeSummary(fields: {
    billing_state: "trial" | "active" | "hibernated";
    capacity_used: number;
    /** WS-B — appended as one further sentence when the route measured them. */
    pricing?: PricingSummary;
    held?: HeldSummary;
}): string;
/**
 * Turn a pay-link 4xx into the structured refusal an agent can act on, or
 * `null` when the caller must keep propagating it — 5xx, timeouts, network
 * failures, and any 403 whose body carries no message worth quoting.
 *
 * The 403 branch is the delicate one: exactly one 403 on this path is about
 * money, and the rest are about access. See its comment.
 *
 * Exported for unit tests.
 */
export declare function payRefusal(err: unknown, offer: PayOffer, entityId?: string): ToolResult | null;
/**
 * Pull the route's JSON body back out of an `ApiError`. The SDK folds the
 * response text into the message (`"API request failed: 400 <body>"`, and
 * `"Authentication failed: 403 <body>"` on the auth path) rather than
 * carrying a structured body — the same extraction `duplicates.ts` and
 * `integrity.ts` do. Returns `{}` when the body is absent or not JSON, so
 * every caller reads a `code` of `undefined` rather than throwing twice.
 *
 * Exported for unit tests.
 */
export declare function parsePayErrorBody(err: ApiError): Record<string, unknown>;
export declare class SubscriptionTools {
    private pica;
    constructor(pica: PicaClient);
    getTools(): Array<{
        definition: ToolDefinition;
        executor: ToolExecutor;
    }>;
    /**
     * `pica_billing_pay` — hand the caller a link, and never a charge.
     *
     * The refusals the ROUTE composes (the flag is off; nothing is held on that
     * work; that offer no longer applies) become structured results rather than
     * thrown ApiErrors — a throw reaches the agent as UNKNOWN_ERROR, which
     * reads as "pica is broken" when the honest answer is "there is nothing to
     * pay for". `payRefusal` decides; everything it declines (5xx, timeouts,
     * network failures, and a 403 with nothing quotable in it) is re-thrown
     * unchanged, because an outage dressed as a tidy refusal is the worse lie.
     */
    private pay;
    private status;
    private manage;
}
export {};
//# sourceMappingURL=subscription.d.ts.map