var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { asDefined, DefaultObservableValue, isDefined, Lazy, panic, RuntimeNotifier, tryCatch, UUID } from "@opendaw/lib-std";
import { network, Promises } from "@opendaw/lib-runtime";
import { base64Credentials, OpenDAWHeaders } from "../OpenDAWHeaders";
/** @internal */
export class OpenPresetAPI {
    static ApiRoot = "https://api.opendaw.studio/presets";
    static FileRoot = "https://assets.opendaw.studio/presets";
    static get() { return new OpenPresetAPI(); }
    constructor() { }
    async list() {
        const url = `${OpenPresetAPI.FileRoot}/index.json?t=${Date.now()}`;
        const result = await Promises.tryCatch(Promises.retry(() => network.defaultFetch(url, OpenDAWHeaders).then(response => response.json())));
        if (result.status === "rejected") {
            console.warn("OpenPresetAPI.list fetch failed", url, result.error);
            return [];
        }
        if (!Array.isArray(result.value)) {
            console.warn("OpenPresetAPI.list unexpected payload", result.value);
            return [];
        }
        console.info(`OpenPresetAPI.list loaded ${result.value.length} cloud preset(s)`);
        return result.value;
    }
    async load(uuid, progress, signal) {
        const url = `${OpenPresetAPI.FileRoot}/${UUID.toString(uuid)}.odp`;
        // Cancellable fetches skip the auto-retry: a user-cancelled download
        // must not silently retry after the dialog has already closed.
        const response = isDefined(signal)
            ? await network.limitFetch(url, { ...OpenDAWHeaders, signal })
            : await Promises.retry(() => network.limitFetch(url, OpenDAWHeaders));
        if (!response.ok) {
            return panic(`Failed to fetch preset ${UUID.toString(uuid)}: ${response.status} ${response.statusText}`);
        }
        if (!isDefined(progress)) {
            return response.arrayBuffer();
        }
        const total = parseInt(response.headers.get("Content-Length") ?? "0");
        let loaded = 0;
        return new Promise((resolve, reject) => {
            const reader = asDefined(response.body, "No body in response").getReader();
            const chunks = [];
            const onAbort = () => reader.cancel().catch(() => { });
            if (isDefined(signal)) {
                signal.addEventListener("abort", onAbort, { once: true });
            }
            const cleanup = () => {
                if (isDefined(signal)) {
                    signal.removeEventListener("abort", onAbort);
                }
            };
            const nextChunk = ({ done, value }) => {
                if (done) {
                    cleanup();
                    resolve(new Blob(chunks).arrayBuffer());
                }
                else {
                    chunks.push(value);
                    loaded += value.length;
                    progress(total > 0.0 ? loaded / total : 0.5);
                    reader.read().then(nextChunk, reason => { cleanup(); reject(reason); });
                }
            };
            reader.read().then(nextChunk, reason => { cleanup(); reject(reason); });
        });
    }
    async upload(arrayBuffer, meta) {
        const progress = new DefaultObservableValue(0.0);
        const dialog = RuntimeNotifier.progress({ headline: "Uploading", progress });
        const formData = new FormData();
        Object.entries(meta).forEach(([key, value]) => formData.set(key, String(value)));
        const params = new URLSearchParams(location.search);
        const accessKey = asDefined(params.get("access-key"), "Cannot upload without access-key.");
        formData.set("key", accessKey);
        formData.append("file", new Blob([arrayBuffer]));
        const xhr = new XMLHttpRequest();
        xhr.upload.addEventListener("progress", (event) => {
            if (event.lengthComputable) {
                progress.setValue(event.loaded / event.total);
            }
        });
        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                dialog.terminate();
                if (xhr.status === 200) {
                    RuntimeNotifier.info({ message: xhr.responseText });
                }
                else {
                    const { status, value } = tryCatch(() => JSON.parse(xhr.responseText).message ?? "Unknown error message");
                    RuntimeNotifier.info({
                        headline: "Upload Failure",
                        message: status === "success" ? value : "Unknown error"
                    });
                }
            }
        };
        xhr.open("POST", `${OpenPresetAPI.ApiRoot}/upload.php`, true);
        xhr.setRequestHeader("Authorization", `Basic ${base64Credentials}`);
        xhr.send(formData);
    }
}
__decorate([
    Lazy,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], OpenPresetAPI.prototype, "list", null);
__decorate([
    Lazy,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", OpenPresetAPI)
], OpenPresetAPI, "get", null);
