export type BuiltInKeyword = keyof typeof MODEL_FILE_MAP;
export type KeywordName = BuiltInKeyword | (string & {});

export interface WakeWordEngineOptions {
    /**
     * Keywords to load and keep warm. Use `setActiveKeywords` to gate detections at runtime.
     * Defaults to ['hey_jarvis'].
     */
    keywords?: KeywordName[];
    /**
     * Mapping of keyword names to ONNX filenames. Defaults to MODEL_FILE_MAP.
     */
    modelFiles?: Record<KeywordName, string>;
    /**
     * Base URL where the .onnx files live. Defaults to "/models".
     */
    baseAssetUrl?: string;
    /**
     * When hosting onnxruntime-web binaries yourself, point to the folder (e.g. "/openwakeword/ort/").
     */
    ortWasmPath?: string;
    /**
     * PCM chunk size, defaults to 1280 samples (80 ms @ 16 kHz).
     */
    frameSize?: number;
    /**
     * Sample rate for the AudioContext / VAD, defaults to 16000 Hz.
     */
    sampleRate?: number;
    /**
     * Number of 80 ms frames to keep speech open after VAD drops below 0.5. Defaults to 12.
     */
    vadHangoverFrames?: number;
    /**
     * Keyword score required to emit `detect`. Defaults to 0.5.
     */
    detectionThreshold?: number;
    /**
     * Cooldown after a detection before another can fire (ms). Defaults to 2000.
     */
    cooldownMs?: number;
    /**
     * Execution providers for onnxruntime-web sessions. WASM-only by default.
     */
    executionProviders?: Array<'wasm' | 'webgl' | 'webgpu' | (string & {})>;
    /**
     * Fallback embedding window size used before model metadata is known. Defaults to 16.
     */
    embeddingWindowSize?: number;
    /**
     * When true, console.debug statements from the engine are enabled.
     */
    debug?: boolean;
}

export interface WakeWordEngineStartOptions {
    deviceId?: string;
    gain?: number;
}

export interface DetectEventPayload {
    keyword: string;
    score: number;
    at: number;
}

export interface WakeWordEngineEventMap {
    ready: void;
    detect: DetectEventPayload;
    'speech-start': void;
    'speech-end': void;
    error: Error;
}

export type WakeWordEngineEvent = keyof WakeWordEngineEventMap;
export type WakeWordEngineEventHandler<E extends WakeWordEngineEvent> =
    WakeWordEngineEventMap[E] extends void ? () => void : (payload: WakeWordEngineEventMap[E]) => void;

export declare const MODEL_FILE_MAP: {
    readonly alexa: 'alexa_v0.1.onnx';
    readonly hey_mycroft: 'hey_mycroft_v0.1.onnx';
    readonly hey_jarvis: 'hey_jarvis_v0.1.onnx';
    readonly hey_rhasspy: 'hey_rhasspy_v0.1.onnx';
    readonly timer: 'timer_v0.1.onnx';
    readonly weather: 'weather_v0.1.onnx';
};

export declare class WakeWordEngine {
    constructor(options?: WakeWordEngineOptions);

    load(): Promise<void>;
    start(options?: WakeWordEngineStartOptions): Promise<void>;
    stop(): Promise<void>;
    setGain(value: number): void;
    runWav(buffer: ArrayBuffer): Promise<number>;
    setActiveKeywords(keywords?: KeywordName[]): void;

    on<E extends WakeWordEngineEvent>(event: E, handler: WakeWordEngineEventHandler<E>): () => void;
    off<E extends WakeWordEngineEvent>(event: E, handler: WakeWordEngineEventHandler<E>): void;
}

export default WakeWordEngine;
