import { ChangeDetectionStrategy, Component, ElementRef, inject, OnInit, viewChild } from '@angular/core';
import { DOSSIER_TEMPLATE_ID, IPlaceholdersResponse, IReportTemplate, User } from '@red/domain';
import { download } from '@utils/file-download-utils';
import {
    CircleButtonComponent,
    getConfig,
    HasScrollbarDirective,
    IConfirmationDialogData,
    IqserAllowDirective,
    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';
import { AsyncPipe } from '@angular/common';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { SnakeCasePipe } from '@common-ui/pipes/snake-case.pipe';

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,
    standalone: true,
    imports: [HasScrollbarDirective, AsyncPipe, TranslateModule, CircleButtonComponent, IqserAllowDirective, SnakeCasePipe],
})
export default class ReportsScreenComponent implements OnInit {
    readonly placeholders$ = new BehaviorSubject<Placeholder[]>([]);
    readonly availableTemplates$ = new BehaviorSubject<IReportTemplate[]>([]);
    readonly currentUser = getCurrentUser<User>();
    readonly roles = Roles;
    readonly isDocumine = getConfig().IS_DOCUMINE;
    readonly #translateService = inject(TranslateService);
    private readonly _fileInput = viewChild<ElementRef>('fileInput');
    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;
    }

    #getAttributeName(placeholder: string): string {
        return removeBraces(placeholder).split('.').pop();
    }

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

    #getTemplateFilename(template: IReportTemplate): string {
        const extensionIndex = template.fileName.lastIndexOf('.');
        const hasExtension = extensionIndex !== -1;

        const baseName = hasExtension ? template.fileName.substring(0, extensionIndex) : template.fileName;
        const extension = hasExtension ? template.fileName.substring(extensionIndex) : '';

        const multiFileSuffix = template.multiFileReport ? ` ${this.#translateService.instant(_('reports-screen.multi-file-report'))}` : '';

        return `${baseName}${multiFileSuffix}${extension}`.trim();
    }

    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);
            }
        });
    }

    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();
    }

    async #deleteTemplate(template: IReportTemplate) {
        await firstValueFrom(this._reportTemplateService.delete(template.dossierTemplateId, template.templateId));
        await this.#loadReportTemplates();
    }

    async #loadReportTemplates() {
        const reportTemplates = await this._reportTemplateService.getAvailableReportTemplates(this.#dossierTemplateId);
        this.availableTemplates$.next(
            reportTemplates.map(template => ({
                ...template,
                fileName: this.#getTemplateFilename(template),
            })),
        );
    }

    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),
                })),
            ),
        );
    }

    #isValidFile(file: File): boolean {
        return this.#isExcelFile(file) || this.#isWordFile(file);
    }

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

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