import { AXComponent } from '@acorex/cdk/common';
import { AXTranslatorPipe, AXTranslationModule } from '@acorex/core/translation';
import { isPlatformBrowser, NgStyle, AsyncPipe, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { input, output, signal, inject, NgZone, PLATFORM_ID, afterNextRender, ViewChild, ViewEncapsulation, Component, NgModule } from '@angular/core';
import WaveSurfer from 'wavesurfer.js';
import { AXButtonModule } from '@acorex/components/button';
import { AXDecoratorModule } from '@acorex/components/decorators';
import { AXSkeletonModule } from '@acorex/components/skeleton';

/**
 * Displays and interacts with audio waveform visualization.
 *
 * @category Components
 */
class AXAudioWaveComponent {
    /**
     *  @ignore
     */
    constructor() {
        /**
         * Configuration settings for the audio wave.
         */
        this.config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : []));
        /**
         * Emits an event when the status of the audio wave changes.
         *
         * @event
         */
        this.onStatusChanged = output();
        this.audioState = signal('paused', ...(ngDevMode ? [{ debugName: "audioState" }] : []));
        this.errorMessage = signal('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
        /**
         *  @ignore
         */
        this.ngZone = inject(NgZone);
        this.platformID = inject(PLATFORM_ID);
        afterNextRender(() => {
            if (isPlatformBrowser(this.platformID)) {
                const primary200 = getComputedStyle(document.body).getPropertyValue('--ax-sys-color-primary-200');
                const primary700 = getComputedStyle(document.body).getPropertyValue('--ax-sys-color-primary-700');
                this.audio = WaveSurfer.create({
                    container: this.div.nativeElement,
                    waveColor: this.config()?.waveColor || `rgba(${primary200})`,
                    progressColor: this.config()?.progressColor || `rgba(${primary700})`,
                    url: this.config()?.url || '',
                    barWidth: this.config()?.barWidth || 2,
                    barRadius: this.config()?.barRadius || 2,
                    barGap: this.config()?.barGap || 2,
                    height: this.config()?.height || 36,
                });
            }
            this.load();
            this.audio?.on('loading', () => {
                this.audioState.set('loading');
            });
            this.audio?.on('ready', () => {
                this.audioState.set('ready');
            });
            this.audio?.on('error', (e) => {
                this.errorMessage.set(e?.message);
                this.audioState.set('error');
            });
            this.bindEvents();
        });
    }
    /**
     * Loads the audio from the specified URL.
     *
     * @param url - The URL of the audio to load. Defaults to the URL from the config.
     */
    load(url = this.config().url) {
        this.audio.load(url);
    }
    /**
     * Plays the audio.
     *
     */
    play() {
        return this.audio?.play();
    }
    /**
     * Pauses the audio.
     */
    pause() {
        this.audio?.pause();
    }
    /**
     * Retrieves the duration of the audio.
     *
     */
    getDuration() {
        return this.audio?.getDuration() ?? 0;
    }
    /**
     * Retrieves the media element of the audio.
     *
     */
    getMediaElement() {
        return this.audio?.getMediaElement();
    }
    /**
     * Sets the playback rate of the audio.
     *
     * @param rate - The playback rate to set.
     */
    setRate(rate) {
        this.audio.setPlaybackRate(rate);
    }
    /**
     *  @ignore
     */
    bindEvents() {
        this.handleLoad();
        this.handleLoading();
        this.handleDecode();
        this.handleReady();
        this.handleRedRawComplete();
        this.handlePlay();
        this.handlePause();
        this.handleFinish();
        this.handleTimeUpdate();
        this.handleSeeking();
        this.handleInteraction();
        this.handleClick();
        this.handleDrag();
        this.handleScroll();
        this.handleZoom();
        this.handleDestroy();
        this.handleError();
    }
    /** When audio starts loading */
    handleLoad() {
        this.audio?.on('load', (url) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { url: url },
                    status: 'load',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** During audio loading */
    handleLoading() {
        this.audio?.on('loading', (percent) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { percent: percent },
                    status: 'loading',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the audio has been decoded */
    handleDecode() {
        this.audio?.on('decode', (duration) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { duration: duration },
                    status: 'decode',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the audio is both decoded and can play */
    handleReady() {
        this.audio?.on('ready', (duration) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { duration: duration },
                    status: 'ready',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When all audio channel chunks of the waveform have drawn */
    handleRedRawComplete() {
        this.audio?.on('redrawcomplete', () => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: null,
                    status: 'redrawcomplete',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the audio starts playing */
    handlePlay() {
        this.audio?.on('play', () => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({ component: this, data: null, status: 'play', isUserInteraction: false });
            });
        });
    }
    /** When the audio pauses */
    handlePause() {
        this.audio?.on('pause', () => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({ component: this, data: null, status: 'pause', isUserInteraction: false });
            });
        });
    }
    /** When the audio finishes playing */
    handleFinish() {
        this.audio?.on('finish', () => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: null,
                    status: 'finish',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** On audio position change, fires continuously during playback */
    handleTimeUpdate() {
        this.audio?.on('timeupdate', (currentTime) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { currentTime: currentTime },
                    status: 'timeupdate',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the user seeks to a new position */
    handleSeeking() {
        this.audio?.on('seeking', (currentTime) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { currentTime: currentTime },
                    status: 'seeking',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the user interacts with the waveform (i.g. clicks or drags on it) */
    handleInteraction() {
        this.audio?.on('interaction', (newTime) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { newTime: newTime },
                    status: 'interaction',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the user clicks on the waveform */
    handleClick() {
        this.audio?.on('click', (relativeX) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { relativeX: relativeX },
                    status: 'click',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the user drags the cursor */
    handleDrag() {
        this.audio?.on('drag', (relativeX) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { relativeX: relativeX },
                    status: 'drag',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the waveform is scrolled (panned) */
    handleScroll() {
        this.audio?.on('scroll', (visibleStartTime, visibleEndTime) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { visibleStartTime, visibleEndTime },
                    status: 'scroll',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** When the zoom level changes */
    handleZoom() {
        this.audio?.on('zoom', (minPxPerSec) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: { minPxPerSec: minPxPerSec },
                    status: 'zoom',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** Just before the waveform is destroyed so you can clean up your events */
    handleDestroy() {
        this.audio?.on('destroy', () => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({
                    component: this,
                    data: null,
                    status: 'destroy',
                    isUserInteraction: false,
                });
            });
        });
    }
    /** Just before the waveform is destroyed so you can clean up your events */
    handleError() {
        this.audio?.on('error', (e) => {
            this.ngZone.run(() => {
                this.onStatusChanged.emit({ component: this, data: e, status: 'error', isUserInteraction: false });
            });
        });
    }
    ngOnDestroy() {
        this.audio.destroy();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXAudioWaveComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: AXAudioWaveComponent, isStandalone: true, selector: "ax-audio-wave", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onStatusChanged: "onStatusChanged" }, providers: [{ provide: AXComponent, useExisting: AXAudioWaveComponent }], viewQueries: [{ propertyName: "div", first: true, predicate: ["d"], descendants: true }], ngImport: i0, template: "<div class=\"ax-audio-wave\" #d [ngStyle]=\"{ display: audioState() === 'ready' ? 'block' : 'none' }\"></div>\n\n@switch (audioState()) {\n  @case ('loading') {\n    <div class=\"ax-audio-skeleton\"></div>\n  }\n  @case ('error') {\n    <div class=\"ax-wave-message\">\n      {{ '@acorex:error.message' | translate: { params: { message: errorMessage() } } | async }}\n    </div>\n  }\n}\n", styles: ["ax-audio-wave{display:block;width:100%;flex:1;--ax-audio-skeleton-bg: rgba(var(--ax-sys-color-primary-200))}ax-audio-wave .ax-audio-skeleton{position:relative;display:block;overflow:hidden;background-color:var(--ax-audio-skeleton-bg);height:1.125rem;border-radius:999rem}ax-audio-wave .ax-audio-skeleton:before{position:absolute;inset-inline-start:-13rem;top:0;display:block;height:100%;width:14rem;content:\"\";background:linear-gradient(to right,transparent 0%,rgba(var(--ax-sys-color-dark-surface),20%) 50%,transparent 100%);animation:load 1s cubic-bezier(.4,0,.2,1) infinite}@keyframes load{0%{inset-inline-start:-13rem}to{inset-inline-start:100%}}ax-audio-wave .ax-wave-message{padding-inline-start:.5rem}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: AXTranslatorPipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXAudioWaveComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ax-audio-wave', encapsulation: ViewEncapsulation.None, imports: [NgStyle, AsyncPipe, AXTranslatorPipe], providers: [{ provide: AXComponent, useExisting: AXAudioWaveComponent }], template: "<div class=\"ax-audio-wave\" #d [ngStyle]=\"{ display: audioState() === 'ready' ? 'block' : 'none' }\"></div>\n\n@switch (audioState()) {\n  @case ('loading') {\n    <div class=\"ax-audio-skeleton\"></div>\n  }\n  @case ('error') {\n    <div class=\"ax-wave-message\">\n      {{ '@acorex:error.message' | translate: { params: { message: errorMessage() } } | async }}\n    </div>\n  }\n}\n", styles: ["ax-audio-wave{display:block;width:100%;flex:1;--ax-audio-skeleton-bg: rgba(var(--ax-sys-color-primary-200))}ax-audio-wave .ax-audio-skeleton{position:relative;display:block;overflow:hidden;background-color:var(--ax-audio-skeleton-bg);height:1.125rem;border-radius:999rem}ax-audio-wave .ax-audio-skeleton:before{position:absolute;inset-inline-start:-13rem;top:0;display:block;height:100%;width:14rem;content:\"\";background:linear-gradient(to right,transparent 0%,rgba(var(--ax-sys-color-dark-surface),20%) 50%,transparent 100%);animation:load 1s cubic-bezier(.4,0,.2,1) infinite}@keyframes load{0%{inset-inline-start:-13rem}to{inset-inline-start:100%}}ax-audio-wave .ax-wave-message{padding-inline-start:.5rem}\n"] }]
        }], ctorParameters: () => [], propDecorators: { div: [{
                type: ViewChild,
                args: ['d', { static: false }]
            }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], onStatusChanged: [{ type: i0.Output, args: ["onStatusChanged"] }] } });

class AXAudioWaveModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXAudioWaveModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: AXAudioWaveModule, imports: [CommonModule,
            AXButtonModule,
            AXDecoratorModule,
            AXSkeletonModule,
            AXTranslationModule,
            AXAudioWaveComponent], exports: [AXAudioWaveComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXAudioWaveModule, imports: [CommonModule,
            AXButtonModule,
            AXDecoratorModule,
            AXSkeletonModule,
            AXTranslationModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AXAudioWaveModule, decorators: [{
            type: NgModule,
            args: [{
                    exports: [AXAudioWaveComponent],
                    imports: [
                        CommonModule,
                        AXButtonModule,
                        AXDecoratorModule,
                        AXSkeletonModule,
                        AXTranslationModule,
                        AXAudioWaveComponent,
                    ],
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { AXAudioWaveComponent, AXAudioWaveModule };
//# sourceMappingURL=acorex-components-audio-wave.mjs.map
