import { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { DOSSIER_TEMPLATE_ID, IPlaceholdersResponse, IReportTemplate, User } from '@red/domain';
import { download } from '@utils/file-download-utils';
import { getConfig, IConfirmationDialogData, LoadingService, Toaster } from '@iqser/common-ui';
import { PermissionsService } from '@services/permissions.service';
import {
    generalPlaceholdersDescriptionsTranslations,
    placeholdersDescriptionsTranslations,
} from '@translations/placeholders-descriptions-translations';
import { removeBraces } from '@utils/functions';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { AdminDialogService } from '../../../services/admin-dialog.service';
import { ReportTemplateService } from '@services/report-template.service';
import { BehaviorSubject, firstValueFrom } from 'rxjs';
import { Roles } from '@users/roles';
import { getCurrentUser } from '@iqser/common-ui/lib/users';
import { getParam } from '@iqser/common-ui/lib/utils';

interface Placeholder {
    placeholder: string;
    descriptionTranslation: string;
    attributeName?: string;
}

type PlaceholderType = 'generalPlaceholders' | 'fileAttributePlaceholders' | 'dossierAttributePlaceholders';
const placeholderTypes: PlaceholderType[] = ['generalPlaceholders', 'fileAttributePlaceholders', 'dossierAttributePlaceholders'];

@Component({
    selector: 'redaction-reports-screen',
    templateUrl: './reports-screen.component.html',
    styleUrls: ['./reports-screen.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ReportsScreenComponent implements OnInit {
    @ViewChild('fileInput') private readonly _fileInput: ElementRef;
    readonly placeholders$ = new BehaviorSubject<Placeholder[]>([]);
    readonly availableTemplates$ = new BehaviorSubject<IReportTemplate[]>([]);
    readonly currentUser = getCurrentUser<User>();
    readonly roles = Roles;
    readonly isDocumine = getConfig().IS_DOCUMINE;
    readonly #dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);

    constructor(
        private readonly _reportTemplateService: ReportTemplateService,
        private readonly _dialogService: AdminDialogService,
        private readonly _toaster: Toaster,
        private readonly _loadingService: LoadingService,
        readonly permissionsService: PermissionsService,
    ) {}

    async ngOnInit() {
        this._loadingService.start();
        await this._loadReportTemplates();
        await this._loadPlaceholders();
        this._loadingService.stop();
    }

    async download(template: IReportTemplate) {
        this._loadingService.start();
        try {
            const data = await firstValueFrom(
                this._reportTemplateService.downloadReportTemplate(template.dossierTemplateId, template.templateId, 'response'),
            );
            this._loadingService.stop();
            download(data, template.fileName);
        } catch (error) {
            this._toaster.error(_('error.http.generic'), { params: error });
            this._loadingService.stop();
        }
    }

    deleteTemplate(template: IReportTemplate) {
        this._dialogService.openDialog('confirm', null, () => {
            this._loadingService.loadWhile(this._deleteTemplate(template));
        });
    }

    uploadTemplate($event) {
        const file: File = $event.target.files[0];

        if (!this._isValidFile(file)) {
            this._toaster.error(_('reports-screen.invalid-upload'));
            return;
        }

        const data: IConfirmationDialogData = {
            title: _('confirmation-dialog.upload-report-template.title'),
            question: _('confirmation-dialog.upload-report-template.question'),
            confirmationText: _('confirmation-dialog.upload-report-template.confirmation-text'),
            denyText: _('confirmation-dialog.upload-report-template.deny-text'),
            alternativeConfirmationText: _('confirmation-dialog.upload-report-template.alternate-confirmation-text'),
            translateParams: {
                fileName: file.name,
            },
        };

        this._dialogService.openDialog('confirm', data, null, async (result: number) => {
            if (result) {
                const multiFileReport = result > 1;
                if (
                    this.availableTemplates$.value.some(
                        template => template.fileName === file.name && template.multiFileReport === multiFileReport,
                    )
                ) {
                    await this._openOverwriteConfirmationDialog(file, multiFileReport);
                } else {
                    await this._uploadTemplateForm(file, multiFileReport);
                }
            }
        });

        this._fileInput.nativeElement.value = null;
    }

    private _getAttributeName(placeholder: string): string {
        return removeBraces(placeholder).split('.').pop();
    }

    private _getPlaceholderDescriptionTranslation(type: PlaceholderType, placeholder: string): string {
        return type === 'generalPlaceholders'
            ? generalPlaceholdersDescriptionsTranslations[removeBraces(placeholder)]
            : placeholdersDescriptionsTranslations[type];
    }

    private async _openOverwriteConfirmationDialog(file: File, multiFileReport: boolean): Promise<void> {
        const data: IConfirmationDialogData = {
            title: _('confirmation-dialog.report-template-same-name.title'),
            question: _('confirmation-dialog.report-template-same-name.question'),
            confirmationText: _('confirmation-dialog.report-template-same-name.confirmation-text'),
            denyText: _('confirmation-dialog.report-template-same-name.deny-text'),
            translateParams: {
                fileName: file.name,
            },
        };

        this._dialogService.openDialog('confirm', data, null, async result => {
            if (result) {
                await this._uploadTemplateForm(file, multiFileReport);
            }
        });
    }

    private async _uploadTemplateForm(file: File, multiFileReport: boolean): Promise<void> {
        this._loadingService.start();
        await firstValueFrom(this._reportTemplateService.uploadTemplateForm(this.#dossierTemplateId, multiFileReport, file));
        await this._loadReportTemplates();
        this._loadingService.stop();
    }

    private async _deleteTemplate(template: IReportTemplate) {
        await firstValueFrom(this._reportTemplateService.delete(template.dossierTemplateId, template.templateId));
        await this._loadReportTemplates();
    }

    private async _loadReportTemplates() {
        const reportTemplates = await this._reportTemplateService.getAvailableReportTemplates(this.#dossierTemplateId);
        this.availableTemplates$.next(reportTemplates);
    }

    private async _loadPlaceholders() {
        const placeholdersResponse: IPlaceholdersResponse = await firstValueFrom(
            this._reportTemplateService.getAvailablePlaceholders(this.#dossierTemplateId),
        );
        this.placeholders$.next(
            placeholderTypes.flatMap(type =>
                placeholdersResponse[type].map(placeholder => ({
                    placeholder,
                    descriptionTranslation: this._getPlaceholderDescriptionTranslation(type, placeholder),
                    attributeName: this._getAttributeName(placeholder),
                })),
            ),
        );
    }

    private _isValidFile(file: File): boolean {
        return this._isExcelFile(file) || this._isWordFile(file);
    }

    private _isExcelFile(file: File): boolean {
        return (
            file.type?.toLowerCase() === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
            file.name.toLowerCase().endsWith('.xlsx')
        );
    }

    private _isWordFile(file: File): boolean {
        return (
            file.type?.toLowerCase() === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
            file.name.toLowerCase().endsWith('.docx')
        );
    }
}
