import { EventEmitter } from 'events';
import { Duplex } from 'node:stream';

/**
 * Runtime status information emitted by encoder/decoder progress updates.
 */
interface LameStatus {
    started: boolean;
    finished: boolean;
    progress: number;
    eta?: string;
}
/**
 * Structured option bag accepted by the encoder.
 */
interface LameOptionsBag {
    output: string | "buffer" | "stream";
    raw?: boolean;
    "swap-bytes"?: boolean;
    "swap-channel"?: boolean;
    gain?: number;
    sfreq?: SampleFrequency;
    bitwidth?: BitWidth;
    signed?: boolean;
    unsigned?: boolean;
    "little-endian"?: boolean;
    "big-endian"?: boolean;
    mp1Input?: boolean;
    mp2Input?: boolean;
    mp3Input?: boolean;
    mode?: ChannelMode;
    "to-mono"?: boolean;
    "channel-different-block-sizes"?: boolean;
    freeformat?: boolean;
    "disable-info-tag"?: boolean;
    comp?: number;
    scale?: number;
    "scale-l"?: number;
    "scale-r"?: number;
    "replaygain-fast"?: boolean;
    "replaygain-accurate"?: boolean;
    "no-replaygain"?: boolean;
    "clip-detect"?: boolean;
    preset?: PresetProfile;
    noasm?: NoAsm;
    quality?: QualityLevel;
    "quality-high"?: boolean;
    "fast-encoding"?: boolean;
    bitrate?: BitRate;
    "max-bitrate"?: BitRate;
    "force-bitrate"?: boolean;
    cbr?: boolean;
    abr?: number;
    vbr?: boolean;
    "vbr-quality"?: number;
    "vbr-old"?: boolean;
    "vbr-new"?: boolean;
    "ignore-noise-in-sfb21"?: boolean;
    emp?: Emphasis;
    "mark-as-copyrighted"?: boolean;
    "mark-as-copy"?: boolean;
    "crc-error-protection"?: boolean;
    nores?: boolean;
    "strictly-enforce-ISO"?: boolean;
    lowpass?: number;
    "lowpass-width"?: number;
    highpass?: number;
    "highpass-width"?: number;
    resample?: SampleFrequency;
    "decode-mp3delay"?: number;
    "nogap"?: string[];
    "nogapout"?: string;
    "nogaptags"?: boolean;
    "out-dir"?: string;
    priority?: PriorityLevel;
    disptime?: number | false;
    silent?: boolean;
    quiet?: boolean;
    verbose?: boolean;
    help?: boolean | HelpTopic;
    usage?: boolean | HelpTopic;
    longhelp?: boolean;
    version?: boolean;
    license?: boolean;
    "no-histogram"?: boolean;
    meta?: MetaOptions;
}
type LameStreamMode = "encode" | "decode";
type LameStreamOptions = Omit<LameOptionsBag, "output"> & {
    output?: "stream";
    mode: LameStreamMode;
};
type SampleFrequency = 8 | 11.025 | 12 | 16 | 22.05 | 24 | 32 | 44.1 | 48;
type BitWidth = 8 | 16 | 24 | 32;
type ChannelMode = "s" | "j" | "f" | "d" | "m" | "l" | "r" | "a";
type PriorityLevel = 0 | 1 | 2 | 3 | 4;
type HelpTopic = "id3" | "dev";
type PresetProfile = string | number;
type NoAsm = "mmx" | "3dnow" | "sse";
type QualityLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type BitRate = 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 80 | 96 | 112 | 128 | 144 | 160 | 192 | 224 | 256 | 320;
type Emphasis = "n" | 5 | "c";
type CustomFrameRecord = Record<string, string | number | boolean> | Array<string | [string, string | number | boolean] | {
    id: string;
    value: string | number | boolean;
}>;
interface MetaOptions {
    title?: string;
    artist?: string;
    album?: string;
    year?: string;
    comment?: string;
    track?: string;
    genre?: string;
    "add-id3v2"?: boolean;
    "id3v1-only"?: boolean;
    "id3v2-only"?: boolean;
    "id3v2-latin1"?: boolean;
    "id3v2-utf16"?: boolean;
    "space-id3v1"?: boolean;
    "pad-id3v2"?: boolean;
    "pad-id3v2-size"?: number;
    "genre-list"?: string;
    "ignore-tag-errors"?: boolean;
    custom?: CustomFrameRecord;
}
interface LameProgressEmitter extends EventEmitter {
    on(event: "progress", listener: (status: [number, string?]) => void): this;
    on(event: "finish", listener: () => void): this;
    on(event: "error", listener: (error: Error) => void): this;
    once(event: "progress", listener: (status: [number, string?]) => void): this;
    once(event: "finish", listener: () => void): this;
    once(event: "error", listener: (error: Error) => void): this;
}

/**
 * Translates option objects into the argument list expected by the LAME CLI.
 */
declare class LameOptions {
    private readonly args;
    private useDefaultDisptime;
    /**
     * Validate all options and build argument array for binary
     * @param {Object} options
     */
    constructor(options: LameOptionsBag);
    /**
     * Get all arguments for binary
     */
    getArguments(): string[];
    shouldUseDefaultDisptime(): boolean;
    private raw;
    private swapBytes;
    private swapChannel;
    private gain;
    private sfreq;
    private bitwidth;
    private signed;
    private unsigned;
    private littleEndian;
    private bigEndian;
    private mp1Input;
    private mp2Input;
    private mp3Input;
    private mode;
    private toMono;
    private channelDifferentBlockSize;
    private freeformat;
    private disableInfoTag;
    private nogap;
    private nogapout;
    private nogaptags;
    private outDir;
    private comp;
    private scale;
    private scaleL;
    private scaleR;
    private replaygainFast;
    private replaygainAccurate;
    private noreplaygain;
    private clipDetect;
    private preset;
    private invalidPreset;
    private noasm;
    private quality;
    private qualityHigh;
    private fastEncoding;
    private bitrate;
    private maxBitrate;
    private forceBitrate;
    private cbr;
    private abr;
    private vbr;
    private vbrQuality;
    private vbrOld;
    private vbrNew;
    private ignoreNoiseInSfb21;
    private emp;
    private markAsCopyrighted;
    private markAsCopy;
    private crcErrorProtection;
    private nores;
    private strictlyEnforceIso;
    private lowpass;
    private lowpassWidth;
    private highpass;
    private highpassWidth;
    private resample;
    private decodeMp3Delay;
    private priority;
    private disptime;
    private silent;
    private quiet;
    private verbose;
    private help;
    private usage;
    private longHelp;
    private version;
    private license;
    private noHistogram;
    private helpLike;
    private meta;
    private appendCustomFrames;
}

/**
 * Thin wrapper around the LAME CLI that manages temp files, progress events,
 * and output handling while delegating the heavy lifting to the binary.
 */
declare class Lame {
    private status;
    private readonly emitter;
    private readonly options;
    private readonly builder;
    private filePath?;
    private fileBuffer?;
    private fileBufferTempFilePath?;
    private progressedFilePath?;
    private progressedBuffer?;
    private progressedBufferTempFilePath?;
    private lamePath;
    private tempPath;
    constructor(options: LameOptionsBag);
    setFile(path: string): this;
    setBuffer(file: Buffer | ArrayBuffer | ArrayBufferView): this;
    setLamePath(path: string): this;
    setTempPath(path: string): this;
    getFile(): string;
    getBuffer(): Buffer;
    getEmitter(): LameProgressEmitter;
    getStatus(): LameStatus;
    encode(): Promise<this>;
    decode(): Promise<this>;
    /**
     * Executes the CLI for the provided conversion type, handling buffers, files,
     * and cleanup in case of errors.
     */
    private executeConversion;
    /**
     * Spawns the LAME process and listens to progress updates, resolving once complete.
     */
    private spawnLameAndTrackProgress;
    private normalizeInputBuffer;
    private convertArrayViewToBuffer;
    private convertFloatArrayToBuffer;
    private shouldUseBigEndian;
    private isSignedForBitwidth;
    private clampSample;
    private scaleToSignedInteger;
    private scaleToUnsignedInteger;
    private persistInputBufferToTempFile;
    private toUint8Array;
    private prepareOutputTarget;
    private ensureOutputDirectoryExists;
    private generateTempFilePath;
    private removeTempArtifacts;
}

type LameStreamConfig = Omit<LameStreamOptions, "output"> & {
    binaryPath?: string;
};
declare class LameStream extends Duplex {
    private readonly emitter;
    private readonly status;
    private readonly builder;
    private readonly binaryPath?;
    private readonly kind;
    private child?;
    private isStdoutPaused;
    private hasErrored;
    private finished;
    constructor(options: LameStreamConfig);
    getEmitter(): LameProgressEmitter;
    getStatus(): LameStatus;
    _read(): void;
    _write(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
    _final(callback: (error?: Error | null) => void): void;
    _destroy(error: Error | null, callback: (error?: Error | null) => void): void;
    private initialize;
    private forwardStdout;
    private handleSuccessfulClose;
    private emitStreamError;
    private cleanupChildListeners;
}

/**
 * Attempt to resolve the absolute path to a bundled LAME binary.
 * Returns null when no bundled binary could be found.
 */
declare function resolveBundledLameBinary(): string | null;
declare function resolveBundledLibraryDirectory(): string | null;
/**
 * Resolve the binary to use. Preference order:
 * 1. `LAME_BINARY` environment variable.
 * 2. Bundled prebuilt binary located in `vendor/lame/<platform>-<arch>/`.
 * 3. Fallback to the `lame` executable on PATH.
 */
declare function resolveLameBinary(): string;

export { Lame, LameOptions, type LameOptionsBag, type LameProgressEmitter, type LameStatus, LameStream, type LameStreamOptions, resolveBundledLameBinary, resolveBundledLibraryDirectory, resolveLameBinary };
