import * as i0 from '@angular/core';
import { InjectionToken, input, computed, Inject, Component, EventEmitter, NgModule } from '@angular/core';
import * as i3 from '@c8y/ngx-components';
import { IconDirective, ModalComponent, LoadingComponent, C8yTranslatePipe, BytesPipe, CoreModule, CommonModule } from '@c8y/ngx-components';
import * as i1 from 'ngx-bootstrap/modal';
import * as i2 from '@angular/platform-browser';
import { takeUntil, first } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { gettext } from '@c8y/ngx-components/gettext';

const PRODUCT_EXPERIENCE_FILE_PREVIEW = {
    EVENTS: {
        FILE_PREVIEW: 'filePreview'
    },
    COMPONENTS: {
        FILE_PREVIEW_COMPONENT: 'file-preview'
    },
    ACTIONS: {
        OPEN_PREVIEW: 'openPreview'
    }
};

/**
 * Provides InjectionToken used in FilePreviewModule. This token is used to inject EventEmitter instance, that is
 * shared among all instances of FilePreviewComponent. These components communicate between each other using this
 * emitter, which enables them to clear downloaded files from memory, if other instance of FilePreviewComponent
 * started downloading different file. Value emitted by this EventEmitter is ID of downloaded file.
 */
const DOWNLOAD_EMITTER = new InjectionToken('downloadEmitter');

/**
 * A component which shows a button that opens a modal with the preview of a binary managed object.
 * This component requires CSP 'blob:' rule for img-src and media-src to be set.
 *
 * ```html
 * <c8y-file-preview [mo]="managedObject">
 *     <button customButton>Preview</button>
 * </c8y-file-preview>
 * ```
 * If no custom button provided, the component will use the default search icon button instead.
 *
 */
class FilePreviewComponent {
    constructor(downloadEmitter, modalRef, modalService, sanitizer, filesService, alertService, gainsightService) {
        this.downloadEmitter = downloadEmitter;
        this.modalRef = modalRef;
        this.modalService = modalService;
        this.sanitizer = sanitizer;
        this.filesService = filesService;
        this.alertService = alertService;
        this.gainsightService = gainsightService;
        this.mo = input.required(...(ngDevMode ? [{ debugName: "mo" }] : []));
        this.downloadFn = input(...(ngDevMode ? [undefined, { debugName: "downloadFn" }] : []));
        this.contentType = computed(() => this.resolveContentType(this.mo()), ...(ngDevMode ? [{ debugName: "contentType" }] : []));
        this.progress = {
            totalBytes: 0,
            bufferedBytes: 0,
            percentage: 0,
            bytesPerSecond: 0
        };
        this.BUFFERING_STATUS_TEXT = gettext('{{speed}}/s - {{bufferedBytes}} of {{totalBytes}} buffered ({{percentage}}%)');
        this.destroy$ = new Subject();
        downloadEmitter.pipe(takeUntil(this.destroy$)).subscribe(id => {
            if (this.dataUrl && this.mo().id !== id) {
                this.removeDownloadedFile();
            }
        });
    }
    ngOnDestroy() {
        this.removeDownloadedFile();
        this.destroy$.next(true);
        this.destroy$.complete();
    }
    async openModal(template) {
        this.modalRef = this.modalService.show(template, {
            ariaDescribedby: 'modal-body',
            ariaLabelledBy: 'modal-title',
            ignoreBackdropClick: true
        });
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_FILE_PREVIEW.EVENTS.FILE_PREVIEW, {
            component: PRODUCT_EXPERIENCE_FILE_PREVIEW.COMPONENTS.FILE_PREVIEW_COMPONENT,
            action: PRODUCT_EXPERIENCE_FILE_PREVIEW.ACTIONS.OPEN_PREVIEW
        });
        if (this.dataUrl) {
            return;
        }
        this.downloadEmitter.emit(this.mo().id);
        if (this.downloadFn()) {
            await this.fetchWithDownloadFn();
            return;
        }
        const subscription = this.filesService
            .fetchFileWithProgress$(this.mo())
            .pipe(takeUntil(this.destroy$))
            .subscribe(progress => {
            this.progress = progress;
            if (this.progress.blob) {
                this.dataUrl = URL.createObjectURL(progress.blob);
                this.safeDataUrl = this.sanitizer.bypassSecurityTrustUrl(this.dataUrl);
            }
        }, e => {
            this.modalRef.hide();
            this.alertService.addServerFailure(e);
        });
        this.modalRef.onHide.pipe(first(), takeUntil(this.destroy$)).subscribe(() => {
            subscription.unsubscribe();
        });
    }
    async fetchWithDownloadFn() {
        try {
            const fn = this.downloadFn();
            if (!fn) {
                return;
            }
            const response = await fn();
            const blob = await response.blob();
            this.dataUrl = URL.createObjectURL(blob);
            this.safeDataUrl = this.sanitizer.bypassSecurityTrustUrl(this.dataUrl);
        }
        catch (e) {
            this.modalRef.hide();
            this.alertService.addServerFailure(e);
        }
    }
    removeDownloadedFile() {
        URL.revokeObjectURL(this.dataUrl);
        delete this.dataUrl;
        delete this.safeDataUrl;
    }
    resolveContentType(mo) {
        if (!mo || !mo.hasOwnProperty('c8y_IsBinary')) {
            // eslint-disable-next-line no-console
            console.warn('Provided Managed object is not binary');
            return 'unsupported';
        }
        if (mo.contentType.startsWith('image/')) {
            return 'image';
        }
        else if (mo.contentType.startsWith('video/')) {
            return 'video';
        }
        else if (mo.contentType.startsWith('text/')) {
            // @TODO: Implement in future
            return 'unsupported';
        }
        else if (mo.contentType.startsWith('application/json')) {
            // @TODO: Implement in future
            return 'unsupported';
        }
        return 'unsupported';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FilePreviewComponent, deps: [{ token: DOWNLOAD_EMITTER }, { token: i1.BsModalRef }, { token: i1.BsModalService }, { token: i2.DomSanitizer }, { token: i3.FilesService }, { token: i3.AlertService }, { token: i3.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: FilePreviewComponent, isStandalone: true, selector: "c8y-file-preview", inputs: { mo: { classPropertyName: "mo", publicName: "mo", isSignal: true, isRequired: true, transformFunction: null }, downloadFn: { classPropertyName: "downloadFn", publicName: "downloadFn", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (contentType() !== 'unsupported') {\n  <div\n    class=\"d-inline-block\"\n    (click)=\"openModal(modalTemplate)\"\n  >\n    <div #customButtonRef>\n      <ng-content select=\"[customButton]\"></ng-content>\n    </div>\n\n    @if (!customButtonRef.children.length) {\n      <button\n        class=\"btn btn-default btn-icon\"\n        [title]=\"'Preview file' | translate\"\n        type=\"button\"\n      >\n        <i c8yIcon=\"search\"></i>\n      </button>\n    }\n  </div>\n}\n\n<ng-template #modalTemplate>\n  <c8y-modal\n    class=\"text-break-word\"\n    [title]=\"mo().name\"\n    [customFooter]=\"false\"\n    (onClose)=\"modalRef.hide()\"\n    (onDismiss)=\"modalRef.hide()\"\n    [labels]=\"{ cancel: '', ok: 'Close' | translate }\"\n  >\n    @if (!dataUrl) {\n      <div class=\"text-center d-block\">\n        <c8y-loading\n          layout=\"application\"\n          [progress]=\"progress.percentage\"\n        ></c8y-loading>\n        {{\n          BUFFERING_STATUS_TEXT\n            | translate\n              : {\n                  totalBytes: progress.totalBytes | bytes,\n                  bufferedBytes: progress.bufferedBytes | bytes,\n                  percentage: progress.percentage,\n                  speed: progress.bytesPerSecond | bytes\n                }\n        }}\n      </div>\n    }\n\n    @if (dataUrl) {\n      <div id=\"modal-body\">\n        @switch (contentType()) {\n          @case ('image') {\n            <img\n              class=\"fit-w\"\n              alt=\"safeDataUrl\"\n              [src]=\"safeDataUrl\"\n            />\n          }\n          @case ('video') {\n            <video\n              class=\"fit-w\"\n              controls\n              autoplay\n            >\n              <source [src]=\"safeDataUrl\" />\n              {{ 'Your browser does not support the video tag.' | translate }}\n            </video>\n          }\n          @case ('text') {\n            <!--        @TODO: Implement text viewer-->\n            text\n          }\n          @case ('json') {\n            <!--        @TODO: Implement json viewer-->\n            json\n          }\n        }\n      </div>\n    }\n  </c8y-modal>\n</ng-template>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: BytesPipe, name: "bytes" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FilePreviewComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-file-preview', imports: [IconDirective, ModalComponent, LoadingComponent, C8yTranslatePipe, BytesPipe], template: "@if (contentType() !== 'unsupported') {\n  <div\n    class=\"d-inline-block\"\n    (click)=\"openModal(modalTemplate)\"\n  >\n    <div #customButtonRef>\n      <ng-content select=\"[customButton]\"></ng-content>\n    </div>\n\n    @if (!customButtonRef.children.length) {\n      <button\n        class=\"btn btn-default btn-icon\"\n        [title]=\"'Preview file' | translate\"\n        type=\"button\"\n      >\n        <i c8yIcon=\"search\"></i>\n      </button>\n    }\n  </div>\n}\n\n<ng-template #modalTemplate>\n  <c8y-modal\n    class=\"text-break-word\"\n    [title]=\"mo().name\"\n    [customFooter]=\"false\"\n    (onClose)=\"modalRef.hide()\"\n    (onDismiss)=\"modalRef.hide()\"\n    [labels]=\"{ cancel: '', ok: 'Close' | translate }\"\n  >\n    @if (!dataUrl) {\n      <div class=\"text-center d-block\">\n        <c8y-loading\n          layout=\"application\"\n          [progress]=\"progress.percentage\"\n        ></c8y-loading>\n        {{\n          BUFFERING_STATUS_TEXT\n            | translate\n              : {\n                  totalBytes: progress.totalBytes | bytes,\n                  bufferedBytes: progress.bufferedBytes | bytes,\n                  percentage: progress.percentage,\n                  speed: progress.bytesPerSecond | bytes\n                }\n        }}\n      </div>\n    }\n\n    @if (dataUrl) {\n      <div id=\"modal-body\">\n        @switch (contentType()) {\n          @case ('image') {\n            <img\n              class=\"fit-w\"\n              alt=\"safeDataUrl\"\n              [src]=\"safeDataUrl\"\n            />\n          }\n          @case ('video') {\n            <video\n              class=\"fit-w\"\n              controls\n              autoplay\n            >\n              <source [src]=\"safeDataUrl\" />\n              {{ 'Your browser does not support the video tag.' | translate }}\n            </video>\n          }\n          @case ('text') {\n            <!--        @TODO: Implement text viewer-->\n            text\n          }\n          @case ('json') {\n            <!--        @TODO: Implement json viewer-->\n            json\n          }\n        }\n      </div>\n    }\n  </c8y-modal>\n</ng-template>\n" }]
        }], ctorParameters: () => [{ type: i0.EventEmitter, decorators: [{
                    type: Inject,
                    args: [DOWNLOAD_EMITTER]
                }] }, { type: i1.BsModalRef }, { type: i1.BsModalService }, { type: i2.DomSanitizer }, { type: i3.FilesService }, { type: i3.AlertService }, { type: i3.GainsightService }], propDecorators: { mo: [{ type: i0.Input, args: [{ isSignal: true, alias: "mo", required: true }] }], downloadFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "downloadFn", required: false }] }] } });

const downloadEmitter = new EventEmitter();
class FilePreviewModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FilePreviewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.25", ngImport: i0, type: FilePreviewModule, imports: [CoreModule, CommonModule, FilePreviewComponent], exports: [FilePreviewComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FilePreviewModule, providers: [
            {
                provide: DOWNLOAD_EMITTER,
                useValue: downloadEmitter
            }
        ], imports: [CoreModule, CommonModule, FilePreviewComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: FilePreviewModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [CoreModule, CommonModule, FilePreviewComponent],
                    exports: [FilePreviewComponent],
                    providers: [
                        {
                            provide: DOWNLOAD_EMITTER,
                            useValue: downloadEmitter
                        }
                    ]
                }]
        }] });

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

export { FilePreviewComponent, FilePreviewModule };
//# sourceMappingURL=c8y-ngx-components-file-preview.mjs.map
