import { PPQN, TimeBase } from "@opendaw/lib-dsp";
import { ColorCodes, TrackType } from "@opendaw/studio-adapters";
import { isDefined, panic, quantizeRound, UUID } from "@opendaw/lib-std";
import { AudioClipBox, AudioPitchStretchBox, AudioRegionBox, AudioTimeStretchBox, ValueEventCollectionBox } from "@opendaw/studio-boxes";
import { TransientPlayMode } from "@opendaw/studio-enums";
import { AudioContentHelpers } from "./AudioContentHelpers";
export var AudioContentFactory;
(function (AudioContentFactory) {
    /**
     * Calculates the duration of an audio region based on sample properties.
     * Returns duration in PPQN for stretched regions, or in seconds for non-stretched.
     */
    AudioContentFactory.calculateDuration = (sample, disableQuantize = false) => {
        const { duration: durationInSeconds, bpm } = sample;
        if (bpm === 0) {
            return durationInSeconds;
        }
        const pulses = PPQN.secondsToPulses(durationInSeconds, bpm);
        return disableQuantize ? pulses : quantizeRound(pulses, PPQN.SemiQuaver);
    };
    // --- Region Creation --- //
    AudioContentFactory.createTimeStretchedRegion = (props) => {
        const { boxGraph, playbackRate, transientPlayMode } = props;
        return createRegionWithWarpMarkers(AudioTimeStretchBox.create(boxGraph, UUID.generate(), box => {
            box.transientPlayMode.setValue(transientPlayMode ?? TransientPlayMode.Pingpong);
            box.playbackRate.setValue(playbackRate ?? 1.0);
        }), props);
    };
    AudioContentFactory.createPitchStretchedRegion = (props) => {
        return createRegionWithWarpMarkers(AudioPitchStretchBox.create(props.boxGraph, UUID.generate()), props);
    };
    AudioContentFactory.createNotStretchedRegion = (props) => {
        const { boxGraph, targetTrack, position, audioFileBox, sample: { name, duration: durationInSeconds } } = props;
        const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
        return AudioRegionBox.create(boxGraph, UUID.generate(), box => {
            box.position.setValue(position);
            box.duration.setValue(durationInSeconds);
            box.loopDuration.setValue(durationInSeconds);
            box.regions.refer(targetTrack.regions);
            box.hue.setValue(ColorCodes.forTrackType(targetTrack.type.getValue()));
            box.label.setValue(props.name ?? name);
            box.file.refer(audioFileBox);
            box.events.refer(collectionBox.owners);
            box.timeBase.setValue(TimeBase.Seconds);
            box.gain.setValue(props.gainInDb ?? 0.0);
            box.waveformOffset.setValue(props.waveformOffset ?? 0.0);
        });
    };
    // --- Clip Creation --- //
    AudioContentFactory.createTimeStretchedClip = (props) => {
        const { boxGraph, playbackRate, transientPlayMode } = props;
        return createClipWithWarpMarkers(AudioTimeStretchBox.create(boxGraph, UUID.generate(), box => {
            box.transientPlayMode.setValue(transientPlayMode ?? TransientPlayMode.Pingpong);
            box.playbackRate.setValue(playbackRate ?? 1.0);
        }), props);
    };
    AudioContentFactory.createPitchStretchedClip = (props) => {
        const { boxGraph } = props;
        return createClipWithWarpMarkers(AudioTimeStretchBox.create(boxGraph, UUID.generate()), props);
    };
    AudioContentFactory.createNotStretchedClip = (props) => {
        const { boxGraph, targetTrack, index, audioFileBox, sample: { name, duration: durationInSeconds } } = props;
        const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
        return AudioClipBox.create(boxGraph, UUID.generate(), box => {
            box.timeBase.setValue(TimeBase.Seconds);
            box.duration.setValue(durationInSeconds);
            box.clips.refer(targetTrack.clips);
            box.hue.setValue(ColorCodes.forTrackType(targetTrack.type.getValue()));
            box.waveformOffset.setValue(props.waveformOffset ?? 0.0);
            box.label.setValue(name);
            box.file.refer(audioFileBox);
            box.events.refer(collectionBox.owners);
            box.index.setValue(index);
        });
    };
    // ---- HELPERS ---- //
    const createRegionWithWarpMarkers = (playMode, props) => {
        const { boxGraph, targetTrack, position, audioFileBox, sample } = props;
        if (targetTrack.type.getValue() !== TrackType.Audio) {
            return panic("Cannot create audio-region on non-audio track");
        }
        const { name, duration: durationInSeconds, bpm } = sample;
        const pulses = PPQN.secondsToPulses(durationInSeconds, bpm);
        const durationInPPQN = props.duration ?? (!props.disableQuantize ? quantizeRound(pulses, PPQN.SemiQuaver) : pulses);
        if (isDefined(props.warpMarkers)) {
            AudioContentHelpers.addWarpMarkers(boxGraph, playMode, props.warpMarkers);
        }
        else {
            AudioContentHelpers.addDefaultWarpMarkers(boxGraph, playMode, durationInPPQN, durationInSeconds);
        }
        const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
        return AudioRegionBox.create(boxGraph, UUID.generate(), box => {
            box.position.setValue(position);
            box.duration.setValue(durationInPPQN);
            box.loopDuration.setValue(durationInPPQN);
            box.regions.refer(targetTrack.regions);
            box.waveformOffset.setValue(props.waveformOffset ?? 0.0);
            box.hue.setValue(ColorCodes.forTrackType(targetTrack.type.getValue()));
            box.label.setValue(name);
            box.file.refer(audioFileBox);
            box.events.refer(collectionBox.owners);
            box.timeBase.setValue(TimeBase.Musical);
            box.playMode.refer(playMode);
            box.gain.setValue(props.gainInDb ?? 0.0);
        });
    };
    const createClipWithWarpMarkers = (playMode, props) => {
        const { boxGraph, targetTrack, audioFileBox, sample } = props;
        if (targetTrack.type.getValue() !== TrackType.Audio) {
            return panic("Cannot create audio-region on non-audio track");
        }
        const { name, duration: durationInSeconds, bpm } = sample;
        const pulses = PPQN.secondsToPulses(durationInSeconds, bpm);
        const durationInPPQN = props.duration ?? (!props.disableQuantize ? quantizeRound(pulses, PPQN.SemiQuaver) : pulses);
        if (isDefined(props.warpMarkers)) {
            AudioContentHelpers.addWarpMarkers(boxGraph, playMode, props.warpMarkers);
        }
        else {
            AudioContentHelpers.addDefaultWarpMarkers(boxGraph, playMode, durationInPPQN, durationInSeconds);
        }
        const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
        return AudioClipBox.create(boxGraph, UUID.generate(), box => {
            box.duration.setValue(durationInPPQN);
            box.clips.refer(targetTrack.clips);
            box.hue.setValue(ColorCodes.forTrackType(targetTrack.type.getValue()));
            box.waveformOffset.setValue(props.waveformOffset ?? 0.0);
            box.label.setValue(name);
            box.file.refer(audioFileBox);
            box.events.refer(collectionBox.owners);
            box.timeBase.setValue(TimeBase.Musical);
            box.playMode.refer(playMode);
            box.index.setValue(props.index);
        });
    };
})(AudioContentFactory || (AudioContentFactory = {}));
