// UI-facing lifecycle around the verified, capability-scoped ASR cache. Keeping
// this separate from the legacy Whisper ModelStore prevents an old entry from
// ever being mistaken for one of the new Sherpa capability files.
import { CapabilityModelStore, totalBytes } from "./capability-model-store.js";
export class CapabilityAsrModelController {
    store;
    state = "未下载";
    activeId;
    progress = {};
    error;
    downloadController;
    downloadPromise;
    constructor(store = new CapabilityModelStore()) {
        this.store = store;
    }
    async status(manifest) {
        if (this.activeId === manifest.id && (this.state === "下载中" || this.state === "等待确认" || this.state === "下载失败" || this.state === "查询失败"))
            return this.snapshot(manifest);
        this.state = await this.store.isReady(manifest) ? "已缓存" : "未下载";
        return this.snapshot(manifest);
    }
    async inspect(manifest) {
        this.activeId = manifest.id;
        this.progress = {};
        this.error = undefined;
        try {
            this.state = await this.store.isReady(manifest) ? "已缓存" : "等待确认";
        }
        catch (error) {
            this.state = "查询失败";
            this.error = error instanceof Error ? error.message : String(error);
        }
        return this.snapshot(manifest);
    }
    beginDownload(manifest) {
        if (this.downloadPromise || this.activeId !== manifest.id || this.state !== "等待确认")
            return false;
        const controller = new AbortController();
        this.downloadController = controller;
        this.state = "下载中";
        this.progress = { downloadedBytes: 0 };
        this.error = undefined;
        this.downloadPromise = this.store.download(manifest, controller.signal, (path, loaded) => {
            this.progress = { currentFile: path, downloadedBytes: loaded };
        }).then(() => { this.state = "已缓存"; }).catch((error) => {
            this.state = error instanceof DOMException && error.name === "AbortError" ? "未下载" : "下载失败";
            this.error = this.state === "未下载" ? undefined : error instanceof Error ? error.message : String(error);
        }).finally(() => { this.downloadController = undefined; this.downloadPromise = undefined; });
        return true;
    }
    async cancel(manifest) {
        this.downloadController?.abort();
        await this.downloadPromise?.catch(() => undefined);
        await this.store.remove(manifest);
        this.state = "未下载";
        this.progress = {};
        this.error = undefined;
    }
    async remove(manifest) {
        await this.cancel(manifest);
    }
    async availability(manifest) {
        try {
            return await this.store.isReady(manifest) ? "available" : "unconfigured";
        }
        catch {
            return "corrupt";
        }
    }
    snapshot(manifest) {
        return {
            status: this.state,
            source: `${manifest.modelId}@${manifest.revision}`,
            license: manifest.license,
            executionPath: manifest.backend === "transformers-webgpu" ? "webgpu" : "wasm-cpu",
            totalBytes: totalBytes(manifest),
            ...this.progress,
            error: this.error,
            canDownload: this.state === "等待确认",
            sizeIsEstimate: false,
            modelNames: [manifest.id === "sherpa-en-streaming-20m-int8" ? "英语实时语音识别模型" : manifest.id === "sherpa-ja-reazonspeech-int8" ? "日语实时语音识别模型" : "Whisper Base WebGPU 语音识别模型"],
        };
    }
}
/**
 * A deliberately small aggregate controller used by the automatic language
 * option.  The two recognizers are downloaded serially so downloads remain
 * cancellable and the browser never holds two large model responses in memory.
 */
export class CapabilityAsrModelBundleController {
    manifests;
    store;
    state = "未下载";
    progress = {};
    error;
    controller;
    pending;
    constructor(manifests, store = new CapabilityModelStore()) {
        this.manifests = manifests;
        this.store = store;
    }
    async status() {
        if (this.pending || this.state === "等待确认" || this.state === "下载失败" || this.state === "查询失败")
            return this.snapshot();
        this.state = (await Promise.all(this.manifests.map((manifest) => this.store.isReady(manifest)))).every(Boolean) ? "已缓存" : "未下载";
        return this.snapshot();
    }
    async inspect() {
        this.progress = {};
        this.error = undefined;
        try {
            this.state = (await Promise.all(this.manifests.map((manifest) => this.store.isReady(manifest)))).every(Boolean) ? "已缓存" : "等待确认";
        }
        catch (error) {
            this.state = "查询失败";
            this.error = error instanceof Error ? error.message : String(error);
        }
        return this.snapshot();
    }
    beginDownload() {
        if (this.pending || this.state !== "等待确认")
            return false;
        this.controller = new AbortController();
        this.state = "下载中";
        this.progress = { downloadedBytes: 0 };
        this.error = undefined;
        this.pending = (async () => {
            let completed = 0;
            for (const manifest of this.manifests) {
                await this.store.download(manifest, this.controller.signal, (path, loaded) => { this.progress = { currentFile: path, downloadedBytes: completed + loaded }; });
                completed += totalBytes(manifest);
            }
            this.state = "已缓存";
        })().catch((error) => {
            this.state = error instanceof DOMException && error.name === "AbortError" ? "未下载" : "下载失败";
            this.error = this.state === "下载失败" ? error instanceof Error ? error.message : String(error) : undefined;
        }).finally(() => { this.pending = undefined; this.controller = undefined; });
        return true;
    }
    async cancel() { this.controller?.abort(); await this.pending?.catch(() => undefined); await this.clear(); }
    async clear() { await Promise.all(this.manifests.map((manifest) => this.store.remove(manifest))); this.state = "未下载"; this.progress = {}; this.error = undefined; }
    async availability() { try {
        return (await Promise.all(this.manifests.map((manifest) => this.store.isReady(manifest)))).every(Boolean) ? "available" : "unconfigured";
    }
    catch {
        return "corrupt";
    } }
    snapshot() {
        return { status: this.state, source: this.manifests.map((item) => item.modelId).join(" + "), license: this.manifests.map((item) => item.license).join("；"), executionPath: "wasm-cpu", totalBytes: this.manifests.reduce((sum, item) => sum + totalBytes(item), 0), ...this.progress, error: this.error, canDownload: this.state === "等待确认", sizeIsEstimate: false, modelNames: ["英语实时语音识别模型", "日语实时语音识别模型"] };
    }
}
