import * as i0 from '@angular/core';
import { inject, EventEmitter, forwardRef, ElementRef, Component, Input, ViewChild, Output, HostListener, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import * as i4 from '@ngx-translate/core';
import { TranslateService, TranslateModule } from '@ngx-translate/core';
import { ConfirmationService } from 'primeng/api';
import { isNullOrUndefined } from '@seniorsistemas/angular-components/utils';
import { ImageCropperService, ImageCropperModule } from '@seniorsistemas/angular-components/image-cropper';
import * as i1 from '@seniorsistemas/angular-components/button';
import { ButtonModule } from '@seniorsistemas/angular-components/button';
import * as i2 from '@seniorsistemas/angular-components/thumbnail';
import { ThumbnailModule } from '@seniorsistemas/angular-components/thumbnail';
import * as i3 from 'primeng/confirmdialog';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { CommonModule } from '@angular/common';

/**
 * @description Componente para seleção, edição e remoção de foto de perfil do usuário.
 * Permite ao usuário fazer upload de uma imagem, recortá-la com o {@link ImageCropperService}
 * e confirmar ou remover a foto atual. Implementa {@link ControlValueAccessor} para uso
 * em formulários reativos e template-driven do Angular.
 *
 * @example
 * ```html
 * <s-profile-picture-picker
 *   formControlName="avatar"
 *   subtitle="Formatos aceitos: JPG e PNG"
 *   [maxFileSize]="2097152"
 *   accept="image/jpeg,image/png"
 *   (imageChange)="onImageChange($event)"
 *   (removedImage)="onImageRemoved()" />
 * ```
 *
 * @category Inputs
 */
class ProfilePicturePickerComponent {
    imageCropperService = inject(ImageCropperService);
    confirmationService = inject(ConfirmationService);
    translateService = inject(TranslateService);
    /**
     * @description Título simples exibido quando nenhuma imagem está selecionada.
     */
    simpleTitle;
    /**
     * @description Título de ação exibido como label principal do botão de upload.
     */
    actionTitle;
    /**
     * @description Legenda exibida abaixo do título, descrevendo formatos suportados
     * ou outras orientações para o usuário. Campo obrigatório.
     */
    subtitle;
    /**
     * @description Proporção (aspect ratio) do recorte da imagem.
     * Por exemplo, `1` para quadrado, `16/9` para widescreen.
     *
     * @default 1
     */
    aspectRatio = 1;
    /**
     * @description Configurações de rótulos exibidos no componente de recorte de imagem (cropper).
     * Permite sobrescrever os textos padrão dos botões e instruções do cropper.
     */
    cropperLabelsConfig;
    /**
     * @description Texto do botão de remoção da foto atual.
     * Se não informado, utiliza o label padrão de remoção.
     */
    removeButtonLabel;
    /**
     * @description Texto do botão de troca da foto atual.
     * Se não informado, utiliza o label padrão de alteração.
     */
    changeButtonLabel;
    /**
     * @description Textos personalizados exibidos no diálogo de confirmação
     * ao remover ou substituir a foto. Permite sobrescrever título, mensagem e botões.
     */
    confirmationTexts;
    /**
     * @description Tamanho máximo permitido para o arquivo de imagem, em bytes.
     * Quando o arquivo excede esse limite, o output `invalidFile` é emitido.
     */
    maxFileSize;
    /**
     * @description Tipos MIME aceitos pelo input de arquivo.
     * Exemplo: `"image/jpeg,image/png"`.
     */
    accept;
    /**
     * @description Lista de extensões de arquivo aceitas para validação.
     * Exemplo: `['.jpg', '.jpeg', '.png']`.
     *
     * @default []
     */
    supportedExtensions = [];
    /**
     * @description Imagem atual do componente. Pode ser uma string base64, um objeto
     * {@link ProfilePicturePickerData} com metadados, ou `null` para sem imagem.
     *
     * @default null
     */
    image = null;
    uploadPicture = null;
    info = null;
    thumbnail = null;
    fileInput = null;
    /**
     * @deprecated Use `imageChange` em vez deste output.
     * @description Emitido ao selecionar ou recortar uma nova imagem. Emite a string base64 da imagem.
     */
    changedImage = new EventEmitter();
    /**
     * @description Emitido ao selecionar, recortar ou alterar a imagem.
     * Emite a string base64 ou um objeto {@link ProfilePicturePickerData} com os dados da imagem.
     */
    imageChange = new EventEmitter();
    /**
     * @description Emitido quando o usuário confirma a remoção da foto atual.
     */
    removedImage = new EventEmitter();
    /**
     * @description Emitido quando o arquivo selecionado não passa na validação.
     * Emite um objeto {@link FileValidationErrors} descrevendo os erros encontrados
     * (ex.: tamanho excedido, extensão inválida).
     */
    invalidFile = new EventEmitter();
    get imageBase64() {
        return typeof this.image === 'string' ? this.image : (this.image?.base64 ?? '');
    }
    _onChange;
    _onTouched;
    writeValue(value) {
        this.image = value;
    }
    registerOnChange(onChange) {
        this._onChange = onChange;
    }
    registerOnTouched(onTouched) {
        this._onTouched = onTouched;
    }
    ngOnInit() {
        this._normalizeSuportedExtensions();
    }
    onDragOver(event) {
        event.preventDefault();
        event.stopPropagation();
    }
    onDragLeave(event) {
        event.preventDefault();
        event.stopPropagation();
    }
    onDrop(event) {
        event.preventDefault();
        event.stopPropagation();
        this._onTouched?.();
        const files = [];
        const dataTransferFiles = event.dataTransfer?.files;
        if (!isNullOrUndefined(dataTransferFiles)) {
            for (let i = 0; i < dataTransferFiles?.length; i++) {
                const item = dataTransferFiles.item(i);
                if (!isNullOrUndefined(item)) {
                    files.push(item);
                }
            }
        }
        this._showImageCropper(files);
    }
    // Verificando o redimensionamento para ajustar o design para ficar responsivo.
    onResize() {
        if (this.uploadPicture && this.info && this.thumbnail) {
            const uploadPictureWidth = this._getWidthElement(this.uploadPicture);
            const infoWidth = this._getWidthElement(this.info);
            const thumbnailWidth = this._getWidthElement(this.thumbnail);
            if (thumbnailWidth + infoWidth > uploadPictureWidth) {
                this.uploadPicture.nativeElement.classList.add('upload-picture--small');
            }
            else {
                this.uploadPicture.nativeElement.classList.remove('upload-picture--small');
            }
        }
    }
    selectPhoto() {
        const fileInputElement = this.fileInput?.nativeElement;
        fileInputElement.value = '';
        fileInputElement.click();
        this._onTouched?.();
    }
    removePhoto() {
        this.confirmationService.confirm({
            message: this.confirmationTexts?.removalMessage ??
                this.translateService.instant('platform.angular_components.confirmation_remove_image'),
            acceptLabel: this.confirmationTexts?.removalAcceptLabel ??
                this.translateService.instant('platform.angular_components.remove'),
            rejectLabel: this.confirmationTexts?.removalRejectLabel ??
                this.translateService.instant('platform.angular_components.cancel'),
            header: this.confirmationTexts?.removalHeader ??
                this.translateService.instant('platform.angular_components.remove_image'),
            rejectButtonStyleClass: 'ui-button-secondary',
            accept: () => {
                const fileInputElement = this.fileInput?.nativeElement;
                fileInputElement.value = '';
                this.image = null;
                this.removedImage.emit();
            },
        });
    }
    photoSelected(event) {
        this._showImageCropper(event.srcElement.files);
    }
    _showImageCropper(files) {
        if (!this._validateData(files)) {
            return;
        }
        const file = files[0];
        const fileReader = new FileReader();
        fileReader.readAsDataURL(file);
        fileReader.onloadend = (fileEvent) => {
            this.imageCropperService.show({
                imageSource: fileEvent.target.result,
                croppedImage: (image) => {
                    this.changedImage.emit(image);
                    const data = { source: file, base64: image };
                    // Se o tipo do image for string eu preciso atualizar e mandar para o imageChange uma string.
                    // Se for ProfilePicturePickerData eu preciso mandar o data completo.
                    if (typeof this.image === 'string') {
                        this.image = image;
                        this.imageChange.emit(image);
                    }
                    else {
                        this.image = data;
                        this.imageChange.emit(data);
                    }
                    this._onChange?.(this.image);
                },
                changeImage: () => this.selectPhoto(),
                allowSelectAnother: false,
                aspectRatio: this.aspectRatio,
                ...this.cropperLabelsConfig,
            });
        };
    }
    _normalizeSuportedExtensions() {
        this.supportedExtensions = this.supportedExtensions?.map((extension) => extension.replace('.', '').toLocaleLowerCase());
    }
    _validateData(files) {
        if (!files.length) {
            return false;
        }
        if (files.length > 1) {
            this.invalidFile.emit({ file: null, validation: 'maxFileLimit' });
            return false;
        }
        const file = files[0];
        if (!file.type.includes('image')) {
            this.invalidFile.emit({ file, validation: 'typeInvalid' });
            return false;
        }
        if (!this._validateFileExtension(file)) {
            this.invalidFile.emit({ file, validation: 'unsupportedExtension' });
            return false;
        }
        if (!this._validateFileSize(file)) {
            this.invalidFile.emit({ file, validation: 'maxFileSize' });
            return false;
        }
        return true;
    }
    _validateFileExtension(file) {
        if (this.supportedExtensions?.length) {
            const extension = file.name.split('.').pop()?.toLowerCase() ?? '';
            return this.supportedExtensions.includes(extension);
        }
        return true;
    }
    _validateFileSize(file) {
        if (this.maxFileSize) {
            return file.size <= this.maxFileSize;
        }
        return true;
    }
    _getWidthElement(element) {
        const { left, right } = element.nativeElement.getBoundingClientRect();
        return right - left;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ProfilePicturePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ProfilePicturePickerComponent, selector: "s-profile-picture-picker", inputs: { simpleTitle: "simpleTitle", actionTitle: "actionTitle", subtitle: "subtitle", aspectRatio: "aspectRatio", cropperLabelsConfig: "cropperLabelsConfig", removeButtonLabel: "removeButtonLabel", changeButtonLabel: "changeButtonLabel", confirmationTexts: "confirmationTexts", maxFileSize: "maxFileSize", accept: "accept", supportedExtensions: "supportedExtensions", image: "image" }, outputs: { changedImage: "changedImage", imageChange: "imageChange", removedImage: "removedImage", invalidFile: "invalidFile" }, host: { listeners: { "dragover": "onDragOver($event)", "dragleave": "onDragLeave($event)", "drop": "onDrop($event)", "window:resize": "onResize()" } }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                useExisting: forwardRef(() => ProfilePicturePickerComponent),
                multi: true,
            },
        ], viewQueries: [{ propertyName: "uploadPicture", first: true, predicate: ["uploadPicture"], descendants: true }, { propertyName: "info", first: true, predicate: ["info"], descendants: true }, { propertyName: "thumbnail", first: true, predicate: ["thumbnail"], descendants: true, read: ElementRef }, { propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, read: ElementRef }], ngImport: i0, template: "<p-confirmDialog></p-confirmDialog>\n\n<input\n    #fileInput\n    [accept]=\"accept\"\n    class=\"file-input\"\n    type=\"file\"\n    (change)=\"photoSelected($event)\"\n/>\n<div\n    #uploadPicture\n    class=\"upload-picture\"\n>\n    <s-thumbnail\n        #thumbnail\n        iconClass=\"far fa-user\"\n        [imageSource]=\"imageBase64\"\n        [hasAction]=\"!image\"\n        (click)=\"selectPhoto()\"\n    >\n    </s-thumbnail>\n    <div\n        #info\n        class=\"info\"\n    >\n        @if (image) {\n            <div class=\"buttons\">\n                <s-button\n                    [label]=\"changeButtonLabel || 'platform.angular_components.change_photo' | translate\"\n                    priority=\"primary\"\n                    (clicked)=\"selectPhoto()\"\n                >\n                </s-button>\n                <s-button\n                    [label]=\"removeButtonLabel || 'platform.angular_components.remove' | translate\"\n                    priority=\"secondary\"\n                    (clicked)=\"removePhoto()\"\n                >\n                </s-button>\n            </div>\n        } @else {\n            <p class=\"title\">\n                {{ simpleTitle || 'platform.angular_components.drag_your_photo_or' | translate }}\n                <span\n                    class=\"action-title\"\n                    (click)=\"selectPhoto()\"\n                >\n                    {{ actionTitle || 'platform.angular_components.select_a_file' | translate }}\n                </span>\n            </p>\n        }\n        <p class=\"subtitle\">{{ subtitle }}</p>\n    </div>\n</div>\n", styles: [".file-input{display:none}.upload-picture{display:flex;flex-wrap:wrap}.upload-picture .info{display:flex;flex-direction:column;padding:12px 20px;align-items:flex-start}.upload-picture .info .title{font-family:Open Sans,sans-serif;font-weight:700;font-size:.875rem;line-height:150%;color:#333}.upload-picture .info .title .action-title{cursor:pointer;color:#428bca}.upload-picture .info .buttons{display:flex;gap:8px}.upload-picture .info .buttons s-button{margin:0}.upload-picture .info .subtitle{padding:6px 0;font-family:Open Sans,sans-serif;font-weight:400;font-size:.75rem;line-height:150%;color:#697882;text-align:center}.upload-picture--small .info{align-items:center}.upload-picture--small .info .title,.upload-picture--small .info .subtitle{text-align:center}.upload-picture--small .info .buttons{justify-content:center;flex-wrap:wrap}\n"], dependencies: [{ kind: "component", type: i1.ButtonComponent, selector: "s-button", inputs: ["id", "label", "tooltip", "tooltipPosition", "iconClass", "rightIconClass", "caret", "styleClass", "baseZIndex", "disabled", "auxiliary", "type", "priority", "menuOptions", "size", "slide", "animation", "badge", "iconColor", "menuAriaLabel"], outputs: ["clicked"] }, { kind: "component", type: i2.ThumbnailComponent, selector: "s-thumbnail", inputs: ["id", "size", "imageSource", "imageFallback", "imageAlt", "iconClass", "hasAction", "actionIconClass", "isTile", "isBrand"] }, { kind: "component", type: i3.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position"], outputs: ["onHide"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ProfilePicturePickerComponent, decorators: [{
            type: Component,
            args: [{ selector: 's-profile-picture-picker', providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            useExisting: forwardRef(() => ProfilePicturePickerComponent),
                            multi: true,
                        },
                    ], template: "<p-confirmDialog></p-confirmDialog>\n\n<input\n    #fileInput\n    [accept]=\"accept\"\n    class=\"file-input\"\n    type=\"file\"\n    (change)=\"photoSelected($event)\"\n/>\n<div\n    #uploadPicture\n    class=\"upload-picture\"\n>\n    <s-thumbnail\n        #thumbnail\n        iconClass=\"far fa-user\"\n        [imageSource]=\"imageBase64\"\n        [hasAction]=\"!image\"\n        (click)=\"selectPhoto()\"\n    >\n    </s-thumbnail>\n    <div\n        #info\n        class=\"info\"\n    >\n        @if (image) {\n            <div class=\"buttons\">\n                <s-button\n                    [label]=\"changeButtonLabel || 'platform.angular_components.change_photo' | translate\"\n                    priority=\"primary\"\n                    (clicked)=\"selectPhoto()\"\n                >\n                </s-button>\n                <s-button\n                    [label]=\"removeButtonLabel || 'platform.angular_components.remove' | translate\"\n                    priority=\"secondary\"\n                    (clicked)=\"removePhoto()\"\n                >\n                </s-button>\n            </div>\n        } @else {\n            <p class=\"title\">\n                {{ simpleTitle || 'platform.angular_components.drag_your_photo_or' | translate }}\n                <span\n                    class=\"action-title\"\n                    (click)=\"selectPhoto()\"\n                >\n                    {{ actionTitle || 'platform.angular_components.select_a_file' | translate }}\n                </span>\n            </p>\n        }\n        <p class=\"subtitle\">{{ subtitle }}</p>\n    </div>\n</div>\n", styles: [".file-input{display:none}.upload-picture{display:flex;flex-wrap:wrap}.upload-picture .info{display:flex;flex-direction:column;padding:12px 20px;align-items:flex-start}.upload-picture .info .title{font-family:Open Sans,sans-serif;font-weight:700;font-size:.875rem;line-height:150%;color:#333}.upload-picture .info .title .action-title{cursor:pointer;color:#428bca}.upload-picture .info .buttons{display:flex;gap:8px}.upload-picture .info .buttons s-button{margin:0}.upload-picture .info .subtitle{padding:6px 0;font-family:Open Sans,sans-serif;font-weight:400;font-size:.75rem;line-height:150%;color:#697882;text-align:center}.upload-picture--small .info{align-items:center}.upload-picture--small .info .title,.upload-picture--small .info .subtitle{text-align:center}.upload-picture--small .info .buttons{justify-content:center;flex-wrap:wrap}\n"] }]
        }], propDecorators: { simpleTitle: [{
                type: Input
            }], actionTitle: [{
                type: Input
            }], subtitle: [{
                type: Input,
                args: [{ required: true }]
            }], aspectRatio: [{
                type: Input
            }], cropperLabelsConfig: [{
                type: Input
            }], removeButtonLabel: [{
                type: Input
            }], changeButtonLabel: [{
                type: Input
            }], confirmationTexts: [{
                type: Input
            }], maxFileSize: [{
                type: Input
            }], accept: [{
                type: Input
            }], supportedExtensions: [{
                type: Input
            }], image: [{
                type: Input
            }], uploadPicture: [{
                type: ViewChild,
                args: ['uploadPicture']
            }], info: [{
                type: ViewChild,
                args: ['info']
            }], thumbnail: [{
                type: ViewChild,
                args: ['thumbnail', { read: ElementRef }]
            }], fileInput: [{
                type: ViewChild,
                args: ['fileInput', { read: ElementRef }]
            }], changedImage: [{
                type: Output
            }], imageChange: [{
                type: Output
            }], removedImage: [{
                type: Output
            }], invalidFile: [{
                type: Output
            }], onDragOver: [{
                type: HostListener,
                args: ['dragover', ['$event']]
            }], onDragLeave: [{
                type: HostListener,
                args: ['dragleave', ['$event']]
            }], onDrop: [{
                type: HostListener,
                args: ['drop', ['$event']]
            }], onResize: [{
                type: HostListener,
                args: ['window:resize']
            }] } });

class ProfilePicturePickerModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ProfilePicturePickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ProfilePicturePickerModule, declarations: [ProfilePicturePickerComponent], imports: [CommonModule, TranslateModule, ButtonModule, ThumbnailModule, ImageCropperModule, ConfirmDialogModule], exports: [ProfilePicturePickerComponent] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ProfilePicturePickerModule, providers: [ImageCropperService, ConfirmationService], imports: [CommonModule, TranslateModule, ButtonModule, ThumbnailModule, ImageCropperModule, ConfirmDialogModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ProfilePicturePickerModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [CommonModule, TranslateModule, ButtonModule, ThumbnailModule, ImageCropperModule, ConfirmDialogModule],
                    declarations: [ProfilePicturePickerComponent],
                    exports: [ProfilePicturePickerComponent],
                    providers: [ImageCropperService, ConfirmationService],
                }]
        }] });

const maxFileSize = (size) => {
    return (control) => {
        if (control.value?.source?.size > size) {
            return {
                maxFileSize: true,
            };
        }
        return null;
    };
};
const fileExtension = (extensions) => {
    return (control) => {
        if (extensions.length) {
            const extension = control.value?.source?.name?.split(".").pop().toLowerCase();
            if (extension?.includes(extension)) {
                return {
                    fileExtension: true,
                };
            }
        }
        return null;
    };
};
const Validators = {
    maxFileSize,
    fileExtension,
};

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

export { ProfilePicturePickerComponent, ProfilePicturePickerModule, Validators };
//# sourceMappingURL=seniorsistemas-angular-components-profile-picture-picker.mjs.map
