import { DefaultObservableValue, Option, Terminator } from "@opendaw/lib-std";
import { EngineSettingsSchema } from "@opendaw/studio-adapters";
import { Preferences } from "@opendaw/lib-fusion";
export class EngineFacade {
    #terminator = new Terminator();
    #lifecycle = this.#terminator.own(new Terminator());
    #playbackTimestamp = new DefaultObservableValue(0.0);
    #countInBeatsRemaining = new DefaultObservableValue(0);
    #position = new DefaultObservableValue(0.0);
    #bpm = new DefaultObservableValue(12.0);
    #isPlaying = new DefaultObservableValue(false);
    #isRecording = new DefaultObservableValue(false);
    #isCountingIn = new DefaultObservableValue(false);
    #markerState = new DefaultObservableValue(null);
    #cpuLoad = new DefaultObservableValue(0);
    #preferencesFacade;
    #worklet = Option.None;
    constructor() {
        this.#preferencesFacade = Preferences.facade("engine-preferences", EngineSettingsSchema);
    }
    setWorklet(worklet) {
        this.#worklet = Option.wrap(worklet);
        this.#preferencesFacade.setHost(worklet.preferences);
        this.#lifecycle.terminate();
        this.#lifecycle.ownAll(worklet.playbackTimestamp.catchupAndSubscribe(owner => this.#playbackTimestamp.setValue(owner.getValue())), worklet.countInBeatsRemaining.catchupAndSubscribe(owner => this.#countInBeatsRemaining.setValue(owner.getValue())), worklet.position.catchupAndSubscribe(owner => this.#position.setValue(owner.getValue())), worklet.bpm.catchupAndSubscribe(owner => this.#bpm.setValue(owner.getValue())), worklet.isPlaying.catchupAndSubscribe(owner => this.#isPlaying.setValue(owner.getValue())), worklet.isRecording.catchupAndSubscribe(owner => this.#isRecording.setValue(owner.getValue())), worklet.isCountingIn.catchupAndSubscribe(owner => this.#isCountingIn.setValue(owner.getValue())), worklet.markerState.catchupAndSubscribe(owner => this.#markerState.setValue(owner.getValue())), worklet.cpuLoad.catchupAndSubscribe(owner => this.#cpuLoad.setValue(owner.getValue())));
    }
    assertWorklet() { this.#worklet.unwrap("No worklet available"); }
    releaseWorklet() {
        this.#worklet.ifSome(worklet => worklet.terminate());
        this.#preferencesFacade.releaseHost();
        this.#lifecycle.terminate();
        this.#worklet = Option.None;
    }
    play() {
        this.#worklet.ifSome(worklet => {
            const context = worklet.context;
            if (context.state === "suspended") {
                context.resume().then(() => worklet.play());
            }
            else {
                worklet.play();
            }
        });
    }
    stop(reset = false) { this.#worklet.ifSome(worklet => worklet.stop(reset)); }
    setPosition(position) { this.#worklet.ifSome(worklet => worklet.setPosition(position)); }
    prepareRecordingState(countIn) { this.#worklet.ifSome(worklet => worklet.prepareRecordingState(countIn)); }
    stopRecording() { this.#worklet.ifSome(worklet => worklet.stopRecording()); }
    get position() { return this.#position; }
    get bpm() { return this.#bpm; }
    get isPlaying() { return this.#isPlaying; }
    get isRecording() { return this.#isRecording; }
    get isCountingIn() { return this.#isCountingIn; }
    get playbackTimestamp() { return this.#playbackTimestamp; }
    get countInBeatsRemaining() { return this.#countInBeatsRemaining; }
    get markerState() { return this.#markerState; }
    get cpuLoad() { return this.#cpuLoad; }
    get project() { return this.#worklet.unwrap("No worklet to get project").project; }
    get sampleRate() { return this.#worklet.isEmpty() ? 44_100 : this.#worklet.unwrap().context.sampleRate; }
    get preferences() { return this.#preferencesFacade; }
    get perfBuffer() { return this.#worklet.mapOr(worklet => worklet.perfBuffer, new Float32Array(0)); }
    get perfIndex() { return this.#worklet.mapOr(worklet => worklet.perfIndex, 0); }
    isReady() { return this.#worklet.mapOr(worklet => worklet.isReady(), Promise.resolve()); }
    queryLoadingComplete() {
        return this.#worklet.mapOr(worklet => worklet.queryLoadingComplete(), Promise.resolve(false));
    }
    panic() { this.#worklet.ifSome(worklet => worklet.panic()); }
    sleep() { this.#worklet.ifSome(worklet => worklet.sleep()); }
    wake() { this.#worklet.ifSome(worklet => worklet.wake()); }
    loadClickSound(index, data) {
        this.#worklet.ifSome(worklet => worklet.loadClickSound(index, data));
    }
    setFrozenAudio(uuid, audioData) {
        this.#worklet.ifSome(worklet => worklet.setFrozenAudio(uuid, audioData));
    }
    subscribeClipNotification(observer) {
        return this.#worklet.unwrap("No worklet to subscribeClipNotification").subscribeClipNotification(observer);
    }
    subscribeNotes(observer) {
        return this.#worklet.unwrap("No worklet to subscribeNotes").subscribeNotes(observer);
    }
    ignoreNoteRegion(uuid) {
        this.#worklet.unwrap("No worklet to ignoreNoteRegion").ignoreNoteRegion(uuid);
    }
    noteSignal(signal) {
        this.#worklet.unwrap("No worklet to noteOn").noteSignal(signal);
    }
    scheduleClipPlay(clipIds) {
        this.#worklet.unwrap("No worklet to scheduleClipPlay").scheduleClipPlay(clipIds);
    }
    scheduleClipStop(trackIds) {
        this.#worklet.unwrap("No worklet to scheduleClipStop").scheduleClipStop(trackIds);
    }
    subscribeDeviceMessage(uuid, listener) {
        return this.#worklet.unwrap("No worklet to subscribeDeviceMessage").subscribeDeviceMessage(uuid, listener);
    }
    registerMonitoringSource(uuid, node, numChannels) {
        this.#worklet.ifSome(worklet => worklet.registerMonitoringSource(uuid, node, numChannels));
    }
    unregisterMonitoringSource(uuid) {
        this.#worklet.ifSome(worklet => worklet.unregisterMonitoringSource(uuid));
    }
    terminate() {
        this.releaseWorklet();
        this.#terminator.terminate();
    }
}
