/**
 * Text-to-Speech (TTS) Processing Utility
 *
 * Central orchestrator for all TTS operations across providers.
 * Manages provider-specific TTS handlers and audio generation.
 *
 * @module utils/ttsProcessor
 */
import type { TTSChunk, TTSOptions, TTSResult, TTSHandler, TTSVoice } from "../types/index.js";
import { ErrorCategory, ErrorSeverity } from "../constants/enums.js";
import { NeuroLinkError } from "./errorHandling.js";
/**
 * TTS-specific error codes
 */
export declare const TTS_ERROR_CODES: {
    readonly EMPTY_TEXT: "TTS_EMPTY_TEXT";
    readonly TEXT_TOO_LONG: "TTS_TEXT_TOO_LONG";
    readonly PROVIDER_NOT_SUPPORTED: "TTS_PROVIDER_NOT_SUPPORTED";
    readonly PROVIDER_NOT_CONFIGURED: "TTS_PROVIDER_NOT_CONFIGURED";
    readonly SYNTHESIS_FAILED: "TTS_SYNTHESIS_FAILED";
    readonly INVALID_INPUT: "TTS_INVALID_INPUT";
};
/** Internal signal raised after all buffered segments have been attempted. */
export declare class IncrementalTTSSynthesisError extends Error {
    readonly firstError: unknown;
    readonly failedSegments: readonly number[];
    constructor(firstError: unknown, failedSegments: number[]);
}
/**
 * TTS Error class for text-to-speech specific errors
 */
export declare class TTSError extends NeuroLinkError {
    constructor(options: {
        code: string;
        message: string;
        category?: ErrorCategory;
        severity?: ErrorSeverity;
        retriable?: boolean;
        context?: Record<string, unknown>;
        originalError?: Error;
    });
}
/**
 * TTS processor class for orchestrating text-to-speech operations
 *
 * Follows the same pattern as CSVProcessor, ImageProcessor, and PDFProcessor.
 * Provides a unified interface for TTS generation across multiple providers.
 *
 * @example
 * ```typescript
 * // Register a handler
 * TTSProcessor.registerHandler('google-ai', googleAIHandler);
 *
 * // Check if provider is supported
 * if (TTSProcessor.supports('google-ai')) {
 *   // Provider is registered
 * }
 * ```
 */
export declare class TTSProcessor {
    /**
     * Handler registry mapping provider names to TTS handlers
     *
     * @private
     */
    private static readonly registry;
    /**
     * Default maximum text length for TTS synthesis (in bytes)
     *
     * Providers can override this value by specifying the `maxTextLength` property
     * in their respective `TTSHandler` implementation. If not specified, this default
     * value will be used.
     *
     * @private
     */
    private static readonly DEFAULT_MAX_TEXT_LENGTH;
    /**
     * Register a TTS handler for a specific provider
     *
     * Allows providers to register their TTS implementation at runtime.
     *
     * @param providerName - Provider identifier (e.g., 'google-ai', 'openai')
     * @param handler - TTS handler implementation
     *
     * @example
     * ```typescript
     * const googleHandler: TTSHandler = {
     *   synthesize: async (text, options) => { ... },
     *   getVoices: async (languageCode) => { ... },
     *   isConfigured: () => true
     * };
     *
     * TTSProcessor.registerHandler('google-ai', googleHandler);
     * ```
     */
    static registerHandler(providerName: string, handler: TTSHandler): void;
    /**
     * Get a registered TTS handler by provider name.
     *
     * Exposed publicly so module-level auto-registration code can reuse an
     * already-registered primary handler when backfilling its aliases —
     * see `src/lib/voice/index.ts:registerDefaultTTSHandlers`.
     *
     * @param providerName - Provider identifier
     * @returns Handler instance or undefined if not registered
     */
    static getHandler(providerName: string): TTSHandler | undefined;
    /**
     * List the names of all registered providers.
     */
    static listProviders(): string[];
    /**
     * Removes every registered TTS handler. Primarily for test isolation —
     * production code should not need to call this.
     */
    static clearHandlers(): void;
    /**
     * Check if a provider is supported (has a registered TTS handler)
     *
     * @param providerName - Provider identifier
     * @returns True if handler is registered
     *
     * @example
     * ```typescript
     * if (TTSProcessor.supports('google-ai')) {
     *   console.log('Google AI TTS is supported');
     * }
     * ```
     */
    static supports(providerName: string): boolean;
    /**
     * List the voices a registered provider offers.
     *
     * The counterpart to `synthesize()` for discovery: a caller cannot pass
     * `TTSOptions.voice` without first knowing what the provider will accept,
     * and `getVoices` is optional on `TTSHandler`, so asking the handler
     * directly means every caller re-implements the same two guards. Both
     * failures are reported as typed `TTSError`s rather than a `TypeError` on
     * an absent member.
     *
     * `languageCode` is passed through verbatim; each handler decides what
     * filtering it means. Google and Azure query their APIs with it, OpenAI's
     * voice list is fixed and ignores it.
     *
     * @param providerName - Provider identifier, resolved case-insensitively
     * @param options - Optional language filter
     * @returns The provider's voices
     * @throws TTSError if the provider is not registered or cannot list voices
     *
     * @example
     * ```typescript
     * const voices = await TTSProcessor.getVoices("google-ai", {
     *   languageCode: "en-US",
     * });
     * ```
     */
    static getVoices(providerName: string, options?: {
        languageCode?: string;
    }): Promise<TTSVoice[]>;
    /**
     * Synthesize speech from text using a registered TTS provider
     *
     * Orchestrates the text-to-speech generation process:
     * 1. Validates input text (not empty, within length limits)
     * 2. Looks up the provider handler
     * 3. Verifies provider configuration
     * 4. Delegates synthesis to the provider (timeout handled by provider)
     * 5. Enriches result with metadata
     *
     * **Timeout Handling:**
     * Timeouts are enforced by individual provider implementations (see TTSHandler interface).
     * Providers typically use 30-second timeouts via `withTimeout()` utility or
     * provider-specific timeout mechanisms (e.g., Google Cloud client timeout).
     *
     * @param text - Text to convert to speech
     * @param provider - Provider identifier
     * @param options - TTS configuration options
     * @returns Audio result with buffer and metadata
     * @throws TTSError if validation fails or provider not supported/configured
     *
     * @example
     * ```typescript
     * const result = await TTSProcessor.synthesize("Hello, world!", "google-ai", {
     *   voice: "en-US-Neural2-C",
     *   format: "mp3",
     *   speed: 1.0
     * });
     *
     * console.log(`Generated ${result.size} bytes of ${result.format} audio`);
     * // Save to file or play the audio buffer
     * ```
     */
    static synthesize(text: string, provider: string, options: TTSOptions): Promise<TTSResult>;
    /**
     * Normalize a provider failure into the public `TTSError` shape.
     *
     * Extracted from `synthesize()` so the native streaming path can shape its
     * transport errors identically. A raw provider error reaching the public
     * surface unwrapped loses `retriable` (and the provider-qualified message),
     * which is exactly what a caller keying retry logic off
     * `ttsMetadata.error.retriable` reads.
     */
    private static toSynthesisError;
    /**
     * Open the `tts.synthesize` span that `synthesize()` opens, so a segment
     * served by a handler's native stream emits the same telemetry a buffered
     * segment does.
     */
    private static startSynthesisSpan;
    private static finishSynthesisSpan;
    /**
     * `TTSHandler.synthesizeStream` is declared `unknown`, so a handler may
     * carry anything at all under that name — including a legacy member of an
     * unrelated shape. The native capability is discovered structurally instead:
     * the member must be callable, and what it returns must be async-iterable.
     *
     * Discovery reads consumer-controlled properties, and a property read can
     * itself execute user code (a Proxy trap, a throwing getter) — the member on
     * the handler and the well-known symbol on what it returns alike. Every one
     * of those reads therefore happens inside a try: `resolveNativeStream`
     * guards the whole preflight in one region, and `cancelStream`/
     * `releaseIterator` in `streamCancellation.ts` guard the symbol read they
     * each perform on the unwind path.
     */
    private static isCallableMember;
    private static isNativeStream;
    /**
     * Coerce one fragment yielded by a handler's native stream into the fields
     * this processor forwards, or `undefined` when the fragment is not audio.
     *
     * `TTSHandler.synthesizeStream` is declared `unknown` because ANY narrower
     * type rejects some existing consumer that already carries a member of that
     * name — a Critical Rule 5 break. The type therefore checks nothing at all,
     * and every check happens at runtime instead. Here that means: a
     * fragment must carry a non-empty binary payload, and a reported `format` is
     * honoured only when it names a real audio format, falling back to the
     * requested one. The caller skips an `undefined` result exactly as it skips
     * a zero-length transport read.
     */
    private static normalizeNativeChunk;
    /**
     * Ask a handler for a native stream for one segment, or `undefined` to serve
     * the segment from `synthesize()`.
     *
     * `undefined` is the documented "not incrementally deliverable" signal. A
     * handler that throws instead, or hands back something that is not
     * async-iterable, is buggy — but that is a reason to serve the segment from
     * the buffered path, not to lose it.
     *
     * **Every failure this method anticipates answers `undefined` instead of
     * throwing, and the caller's catch backstops what no code that must
     * describe a hostile thrown value can rule out.** Everything it does is a question ABOUT the
     * handler, asked before any of the segment's work has begun, and every one
     * of those questions can run consumer code: reading `synthesizeStream` or
     * `isConfigured` can hit an accessor or a `Proxy` trap, calling
     * `isConfigured()` and calling the member run handler code outright, and
     * reading `Symbol.asyncIterator` off whatever comes back can hit a getter or
     * a trap of its own. A throw from ANY of them means the same thing — the
     * capability could not be established — so they all sit inside the single
     * guarded region below and every failure answers `undefined`. The segment
     * then goes to `synthesize()`, which re-runs the identical preflight inside
     * its own `tts.synthesize` span and normalizes whatever it raises, exactly
     * as it did before native streaming existed. Reporting a preflight failure
     * from here instead would open a second span for one segment, or drop a
     * segment the buffered path can still serve.
     *
     * Two ordering rules make that equivalence exact:
     *
     * - The member is read FIRST and exactly ONCE per segment. An accessor-
     *   defined member runs consumer code on every read, so a second read can
     *   answer differently from the one that was tested — and reading it before
     *   `isConfigured()` keeps a handler that does not offer the capability at
     *   all on precisely the call sequence it had before this method existed.
     * - `isConfigured()` runs only once a callable member has been found, which
     *   is the only case where this method is about to invoke the handler.
     *
     * The one measured departure from `origin/release` is a call count, not an
     * outcome: a segment that starts down the native path and falls back calls
     * the handler's `isConfigured()` twice — here, and again inside
     * `synthesize()`. That is inherent to attempting native delivery at all and
     * predates this method's current shape; `isConfigured()` is specified as a
     * configuration predicate, and for any implementation that behaves as one —
     * a pure predicate — every observable of such a segment (chunks, spans,
     * error code and `retriable`) is identical either way. A handler whose
     * answer CHANGES between the two calls changes the outcome with it: the
     * second answer, taken on the path that actually synthesizes, decides.
     */
    private static resolveNativeStream;
    /**
     * Incrementally synthesize sentence-buffered text chunks.
     *
     * Text is flushed at a sentence boundary after `streamingBufferSize`
     * characters, or hard-split before the provider's maximum text length.
     *
     * A segment is served by the handler's `synthesizeStream()` when it offers
     * one and returns a stream, and by `synthesize()` otherwise — including
     * when the native stream produces no deliverable audio at all, and including
     * every way capability discovery itself can fail. The preflight reads and
     * calls that decide whether a native stream exists all sit inside one
     * guarded region in `resolveNativeStream`, with the call site's own catch
     * backstopping it, so a handler that misbehaves while being ASKED lands on
     * the buffered path rather than costing the segment. That is what makes the
     * next sentence true of every segment rather than only of the ones that got
     * that far.
     *
     * Either way the segment keeps the same handler registry, validation, error
     * normalization and `tts.synthesize` telemetry seam — exactly one span per
     * segment, opened by whichever path served it — cancellation included: a
     * segment whose stream is still in flight when the consumer stops records
     * its span from the unwind path rather than dropping it. Failures that
     * originate in the native segment's own work, once a stream has been
     * established, are a different case and keep the shaped failed-segment
     * semantics every synthesis failure has.
     *
     * Provider-reported indexes, cumulative sizes and finality are discarded and
     * recomputed globally. A native fragment is dropped unless it carries a
     * non-empty binary payload, so no native read reaches the consumer as an
     * empty chunk; the buffered path is unfiltered and forwards whatever
     * `synthesize()` returns, so a handler that produces a zero-byte buffer
     * still yields an empty chunk and a repeated `cumulativeSize`. The most
     * recent successful audio chunk is held until another succeeds or the input
     * ends, so exactly one real audio chunk carries `isFinal: true` without
     * emitting a separate empty terminator chunk.
     *
     * Segment production and per-segment synthesis are deliberately inline
     * rather than nested async generators: each additional generator layer costs
     * every chunk several microtask turns, which is directly observable at
     * `NeuroLink.stream()` as audio interleaving one text chunk later than it
     * does without native streaming.
     */
    static synthesizeStream(textChunks: AsyncIterable<string>, provider: string, options: TTSOptions, shouldStop?: () => boolean): AsyncGenerator<TTSChunk>;
}
