import { KeyValuePipe, NgForOf, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, Inject, OnInit, signal } from '@angular/core';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { ReplaceNbspPipe } from '@common-ui/pipes/replace-nbsp.pipe';
import { BaseDialogComponent, CircleButtonComponent, EditableInputComponent, IconButtonComponent } from '@iqser/common-ui';
import { TranslateModule } from '@ngx-translate/core';
import { ComponentLogEntry, Dictionary, IFile, WorkflowFileStatuses } from '@red/domain';
import { FilesMapService } from '@services/files/files-map.service';
import { UserPreferenceService } from '@users/user-preference.service';
import { firstValueFrom } from 'rxjs';
import { ComponentLogService } from '@services/files/component-log.service';

interface ScmData {
    file: IFile;
    dictionaries: Dictionary[];
}

@Component({
    templateUrl: './structured-component-management-dialog.component.html',
    styleUrls: ['./structured-component-management-dialog.component.scss'],
    standalone: true,
    changeDetection: ChangeDetectionStrategy.OnPush,
    imports: [
        NgIf,
        EditableInputComponent,
        NgForOf,
        KeyValuePipe,
        TranslateModule,
        CircleButtonComponent,
        IconButtonComponent,
        MatCheckboxModule,
        MatDialogModule,
        ReplaceNbspPipe,
    ],
})
export class StructuredComponentManagementDialogComponent extends BaseDialogComponent implements OnInit {
    readonly componentLogData = signal<ComponentLogEntry[] | undefined>(undefined);
    readonly openScmDialogByDefault = signal(this.userPreferences.getOpenScmDialogByDefault());

    constructor(
        protected readonly _dialogRef: MatDialogRef<StructuredComponentManagementDialogComponent>,
        private readonly _componentLogService: ComponentLogService,
        readonly userPreferences: UserPreferenceService,
        private readonly _filesMapService: FilesMapService,
        @Inject(MAT_DIALOG_DATA) readonly data: ScmData,
    ) {
        super(_dialogRef);
    }

    get canEdit() {
        return this.data.file.workflowStatus !== WorkflowFileStatuses.APPROVED;
    }

    async ngOnInit(): Promise<void> {
        await this.#loadData();
    }

    getValueCellId(index: number) {
        return `value-cell-${index}`;
    }

    originalOrder = (): number => 0;

    exportJSON() {
        return firstValueFrom(
            this._componentLogService.exportJSON(this.data.file.dossierTemplateId, this.data.file.dossierId, this.data.file),
        );
    }

    exportXML() {
        return firstValueFrom(
            this._componentLogService.exportXML(this.data.file.dossierTemplateId, this.data.file.dossierId, this.data.file),
        );
    }

    async exportAllInDossier() {
        const allFilesInDossier = this._filesMapService.get(this.data.file.dossierId);
        for (const file of allFilesInDossier) {
            await firstValueFrom(this._componentLogService.exportJSON(this.data.file.dossierTemplateId, file.dossierId, file));
            await firstValueFrom(this._componentLogService.exportXML(this.data.file.dossierTemplateId, file.dossierId, file));
        }
    }

    save() {
        return this.exportJSON();
    }

    parseType(type: string) {
        return type.replaceAll('_', ' ').replace(/(^\w{1})|(\s+\w{1})/g, letter => letter.toUpperCase());
    }

    async toggleOpenScmDialogByDefault() {
        await this.userPreferences.toggleOpenScmDialogByDefault();
        await this.userPreferences.reload();
        this.openScmDialogByDefault.set(this.userPreferences.getOpenScmDialogByDefault());
    }

    async undo(originalKey: string) {
        this._loadingService.start();
        await firstValueFrom(this._componentLogService.revertOverride(this.data.file.dossierId, this.data.file.fileId, [originalKey]));
        await this.#loadData();
    }

    async saveEdit(event: string, originalKey: string) {
        this._loadingService.start();
        await firstValueFrom(this._componentLogService.override(this.data.file.dossierId, this.data.file.fileId, { [originalKey]: event }));
        await this.#loadData();
    }

    async #loadData(): Promise<void> {
        this._loadingService.start();
        const componentLogData = await firstValueFrom(
            this._componentLogService.getComponentLogData(
                this.data.file.dossierTemplateId,
                this.data.file.dossierId,
                this.data.file.fileId,
            ),
        );
        this.#updateDisplayValue(componentLogData);
        this.componentLogData.set(componentLogData);
        this._loadingService.stop();
    }

    #updateDisplayValue(componentLogs: ComponentLogEntry[]) {
        const dictionaries = this.data.dictionaries;
        for (const componentLog of componentLogs) {
            let foundDictionary: Dictionary;
            for (const reference of componentLog.componentValues[0].entityReferences) {
                if (foundDictionary) {
                    reference.displayValue = foundDictionary.label;
                    continue;
                }
                foundDictionary = dictionaries.find(dict => dict.type === reference.type);
                foundDictionary = foundDictionary ?? ({ label: reference.type } as Dictionary);
                reference.displayValue = foundDictionary.label;
            }
        }
    }
}
