import { ComposeManifest, ComposeCompileRequest, ComposeCompileResult, ComposeRouteRequest, SimulateRequest, SimulateResult } from '@lifi/compose-spec';
import { ChainSummary, GetZapPacksOptions, ZapPackOverview } from './discovery.js';

/**
 * Configuration for creating a low-level Compose API client.
 */
interface ComposeClientOptions {
    /** Base URL of the Compose API. */
    readonly baseUrl: string;
    /** Optional custom `fetch` implementation. Defaults to `globalThis.fetch`. */
    readonly fetch?: typeof globalThis.fetch;
    /** LI.FI API key, sent as the `x-lifi-api-key` header on every request. Required — the Compose API rejects unauthenticated requests. */
    readonly apiKey: string;
}
/**
 * Low-level HTTP client for the Compose API.
 *
 * Handles request serialization, SDK version headers, and error mapping.
 * Prefer using {@link ComposeSdk} for the full builder experience. Use this
 * directly when you need to decouple request building from submission — e.g.
 * build via `sdk.request()` then submit via `client.compile()` with custom
 * retry logic or request inspection.
 */
interface ComposeClient {
    /**
     * Fetches the server's operation manifest describing all supported operations,
     * guards, materialisers, and preconditions.
     * @returns The manifest document.
     * @throws {@link ComposeError} on network, validation, or server errors.
     */
    readonly getManifest: () => Promise<ComposeManifest>;
    /**
     * Fetches the chains the Compose API supports, ascending by `chainId`.
     *
     * A chain is listed once the server confirms the VM contract is deployed on
     * it — the same condition {@link compile}, {@link route} and
     * {@link simulate} validate against. A chain absent from this list is
     * rejected outright by those endpoints.
     *
     * The converse does not hold: a listed chain can still have no routing edge
     * for a given token pair, which {@link route} reports as `no_route_error`.
     * Use {@link getZapPacks} to enumerate the pairs that do route.
     *
     * Each entry carries a display `name` alongside its `chainId`. The name is a
     * deployment-maintained label — render it, but key on `chainId`.
     *
     * The list tracks the server's chain registry, which refreshes periodically.
     * Results are not cached by the SDK; callers should cache as appropriate.
     *
     * @returns The supported chains, ascending by `chainId`.
     * @throws {@link ComposeError} on network or server errors.
     */
    readonly getChains: () => Promise<readonly ChainSummary[]>;
    /**
     * Submits a compile request and returns the result.
     *
     * When the caller passes `simulationPolicy: 'allow-revert'` and the transaction
     * reverts in simulation, the server responds with HTTP 206 and the SDK returns a
     * partial result (`status: 'partial'`) instead of throwing. The partial result
     * includes the transaction (without `gasLimit`) and revert diagnostics.
     *
     * @param request - The full compile request including flow and run inputs.
     * @returns A discriminated result: `status: 'success'` or `status: 'partial'`.
     * @throws {@link ComposeError} on network, validation, or server errors.
     */
    readonly compile: (request: ComposeCompileRequest) => Promise<ComposeCompileResult>;
    /**
     * Compiles a token pair into a submit-ready transaction via
     * `POST /compose/route`.
     *
     * A convenience path that skips flow authoring: the server builds a one-node
     * zap flow with a `directDeposit` input from the `fromToken` / `toToken`
     * pair and runs it through the same pipeline as {@link compile}. The
     * response is therefore the same discriminated result — HTTP 206 under
     * `simulationPolicy: 'allow-revert'` yields `status: 'partial'` rather than
     * throwing, exactly as it does for {@link compile}.
     *
     * As of today that flow is a single zap step: one edge of the backend's
     * routing catalog (a position entry or exit, a wrap or unwrap, a mint or
     * burn). Enumerate the pairs it covers with {@link getZapPacks}; a pair with
     * no edge is rejected with `kind: 'no_route_error'`. The endpoint is meant to
     * author richer flows later, so the single-step limit is the current state of
     * the server, not the shape of this contract.
     *
     * Only synchronous edges are considered unless the request sets
     * `allowAsyncRoutes: true`, so by default every terminal output comes back
     * `delivery.when: 'now'` and a pair reachable only after settlement is a
     * `no_route_error`. Opting in adds the `lifi.zapAsync` fallback, which still
     * loses to a synchronous edge when the pair has one; read
     * `outputs[*].delivery.when` to see which representation you got.
     *
     * Use {@link compile} for what the server does not author for you: several
     * chained operations, splits, explicit preconditions, or per-op guards.
     *
     * `bigint` amounts in `amount` are serialised to decimal strings
     * automatically.
     *
     * @param request - The from/to token pair, amount, signer, and route options.
     * @returns A discriminated result: `status: 'success'` or `status: 'partial'`.
     * @throws {@link ComposeError} on network, validation, or server errors —
     *   including `NOT_FOUND` (HTTP 404) when no catalog edge covers the pair.
     */
    readonly route: (request: ComposeRouteRequest) => Promise<ComposeCompileResult>;
    /**
     * Fetches the available routing edges grouped by protocol.
     *
     * The edge catalog is dynamic — it reflects the current state of the
     * backend's routing snapshot (protocols, chains, token blacklists).
     * Results are not cached by the SDK; callers should cache as appropriate.
     *
     * @param options - Optional filter to restrict results to specific protocols.
     * @returns An array of {@link ZapPackOverview} objects, one per protocol.
     * @throws {@link ComposeError} on network or server errors (503 when the
     *   routing catalog is not yet initialized).
     */
    readonly getZapPacks: (options?: GetZapPacksOptions) => Promise<readonly ZapPackOverview[]>;
    /**
     * Simulates a raw, pre-encoded transaction against `POST /simulate` and
     * reports how the watched balances change and how much inner-call gas it
     * burns.
     *
     * The result is a discriminated union on `status`:
     * - `'ok'` — the simulation ran successfully; `deltas`/`gasUsed` are populated.
     * - `'revert'` — the simulation ran but the transaction reverted on-chain. A
     *   revert is a *successful simulation*, not a transport error, so it is
     *   returned (HTTP 200) rather than thrown — mirroring how {@link compile}
     *   returns `status: 'partial'` on a simulated revert.
     * - `'error'` — the request was well-formed but the simulation could not be
     *   set up or run (HTTP 422); `message` is intentionally generic.
     *
     * `bigint` amounts in the request (`value`, requirement `balance`/`allowance`)
     * are serialised to decimal strings automatically.
     *
     * @param request - The raw transaction plus funding `requirements` and the
     *   `trackedBalances` to watch.
     * @returns A {@link SimulateResult} (`ok` / `revert` / `error`).
     * @throws {@link ComposeError} on network failures, HTTP 400 (malformed
     *   input), 401/403 (auth), 404, 429, and 5xx.
     */
    readonly simulate: (request: SimulateRequest) => Promise<SimulateResult>;
}
/**
 * `JSON.stringify` replacer that renders `bigint` amounts as decimal strings.
 *
 * The compose wire carries token amounts as decimal strings, and `bigint` has
 * no JSON representation, so every payload this client sends goes through it.
 * Exported so the example harness prints a request exactly as it is sent.
 */
declare const bigintReplacer: (_key: string, value: unknown) => unknown;
/**
 * Creates a low-level Compose API client.
 *
 * @param options - Client configuration including the API base URL.
 * @returns A {@link ComposeClient} instance.
 */
declare const createComposeClient: (options: ComposeClientOptions) => ComposeClient;

export { type ComposeClient, type ComposeClientOptions, bigintReplacer, createComposeClient };
