import { NgForOf, NgIf } from '@angular/common';
import { Component, ElementRef, Input, OnInit, QueryList, ViewChildren } from '@angular/core';
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { EmptyStateComponent } from '@common-ui/empty-state';
import { DynamicInputComponent } from '@common-ui/inputs/dynamic-input/dynamic-input.component';
import { SnakeCasePipe } from '@common-ui/pipes/snake-case.pipe';
import { CircleButtonComponent, IconButtonComponent, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { TranslateModule } from '@ngx-translate/core';
import { Dossier, DossierAttributeConfigType, DossierAttributeConfigTypes, DossierAttributeWithValue } from '@red/domain';
import { DossierAttributesService } from '@services/entity-services/dossier-attributes.service';
import { PermissionsService } from '@services/permissions.service';
import dayjs from 'dayjs';
import { firstValueFrom } from 'rxjs';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';

@Component({
    selector: 'redaction-edit-dossier-attributes',
    templateUrl: './edit-dossier-attributes.component.html',
    styleUrls: ['./edit-dossier-attributes.component.scss'],
    standalone: true,
    imports: [
        ReactiveFormsModule,
        NgIf,
        TranslateModule,
        EmptyStateComponent,
        DynamicInputComponent,
        NgForOf,
        IconButtonComponent,
        SnakeCasePipe,
        CircleButtonComponent,
    ],
})
export class EditDossierAttributesComponent implements EditDossierSectionInterface, OnInit {
    @ViewChildren('fileInput') private _fileInputs: QueryList<ElementRef>;
    readonly iconButtonTypes = IconButtonTypes;
    readonly dossierAttributeConfigTypes = DossierAttributeConfigTypes;
    @Input() dossier: Dossier;
    customAttributes: DossierAttributeWithValue[] = [];
    imageAttributes: DossierAttributeWithValue[] = [];
    attributes: DossierAttributeWithValue[] = [];
    form: UntypedFormGroup;
    initialFormValue: { [key: string]: string } = {};

    constructor(
        private readonly _permissionsService: PermissionsService,
        private readonly _dossierAttributesService: DossierAttributesService,
        private readonly _loadingService: LoadingService,
        private readonly _formBuilder: UntypedFormBuilder,
        private readonly _toaster: Toaster,
    ) {}

    get changed() {
        for (const attr of this.attributes) {
            if (this.isSpecificType(attr, this.dossierAttributeConfigTypes.DATE) && attr.value) {
                if (!dayjs(attr.value).isSame(dayjs(this.currentAttrValue(attr)), 'day')) {
                    return true;
                }
            } else if (this.#parseAttrValue(attr.value) !== this.#parseAttrValue(this.currentAttrValue(attr))) {
                return true;
            }
        }

        return false;
    }

    get disabled(): boolean {
        return !this._permissionsService.isOwner(this.dossier) || this.dossier.isArchived;
    }

    get valid(): boolean {
        return !!this.form?.valid;
    }

    async ngOnInit() {
        this._loadingService.start();
        await this.#loadAttributes();
        this.form = this.#getForm();
        this.initialFormValue = this.form.getRawValue();
        this._loadingService.stop();
    }

    async save(): EditDossierSaveResult {
        const dossierAttributeList = this.attributes.map(attr => ({
            dossierAttributeConfigId: attr.id,
            value:
                this.isSpecificType(attr, DossierAttributeConfigTypes.DATE) && !!this.currentAttrValue(attr)
                    ? dayjs(this.currentAttrValue(attr)).format('YYYY-MM-DD')
                    : this.currentAttrValue(attr),
        }));
        try {
            await firstValueFrom(this._dossierAttributesService.setAttributes(this.dossier, dossierAttributeList));
            await firstValueFrom(this._dossierAttributesService.loadAll(this.dossier.dossierTemplateId));
            await this.#loadAttributes();
            this.initialFormValue = this.form.getRawValue();
            return { success: true };
        } catch (error) {
            this._toaster.error(_('edit-dossier-dialog.attributes.error.generic'));
            return { success: false };
        }
    }

    fileInputClick(attr: DossierAttributeWithValue) {
        this.#getFileInputById(attr.id).nativeElement.click();
    }

    isSpecificType(attr: DossierAttributeWithValue, type: DossierAttributeConfigType): boolean {
        return attr.type === type;
    }

    async uploadImage($event, attr: DossierAttributeWithValue) {
        const toBase64 = file =>
            new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.readAsDataURL(file);
                reader.onload = () => resolve(reader.result);
                reader.onerror = error => reject(error);
            });

        const image = $event.target.files[0];
        const result = await toBase64(image);
        this.form.patchValue({
            [attr.id]: result,
        });
        this.#getFileInputById(attr.id).nativeElement.value = null;
    }

    revert() {
        this.#loadAttributes().then(() => this.form.reset(this.initialFormValue));
    }

    currentAttrValue(attr: DossierAttributeWithValue): string {
        return this.form.get(attr.id).value;
    }

    deleteAttr(attr: DossierAttributeWithValue) {
        this.form.patchValue({
            [attr.id]: null,
        });
    }

    #getFileInputById(id: string): ElementRef {
        return this._fileInputs.find(el => el.nativeElement.name === id);
    }

    #parseAttrValue(value: any) {
        return [null, undefined, ''].includes(value) ? undefined : value;
    }

    async #loadAttributes() {
        this.attributes = await this._dossierAttributesService.getWithValues(this.dossier);
        this.customAttributes = this.attributes.filter(attr => !this.isSpecificType(attr, this.dossierAttributeConfigTypes.IMAGE));
        this.imageAttributes = this.attributes.filter(attr => this.isSpecificType(attr, this.dossierAttributeConfigTypes.IMAGE));
    }

    #getForm(): UntypedFormGroup {
        const controlsConfig = {};
        for (const attribute of this.attributes) {
            controlsConfig[attribute.id] = [{ value: attribute.value, disabled: this.disabled }];
        }
        return this._formBuilder.group(controlsConfig);
    }
}
