import { Component, ElementRef, ViewChild } from '@angular/core';
import { HeaderElements } from '../../../file-preview/utils/constants';
import { ConfirmOption, ConfirmOptions, IConfirmationDialogData, LoadingService } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FilesMapService } from '@services/files/files-map.service';
import { SharedDialogService } from '@shared/services/dialog.service';
import { PdfViewer } from '../../services/pdf-viewer.service';
import { ViewerHeaderService } from '../../services/viewer-header.service';
import { REDDocumentViewer } from '../../services/document-viewer.service';
import { Core } from '@pdftron/webviewer';
import { firstValueFrom } from 'rxjs';
import { MatDialogRef } from '@angular/material/dialog';
import { processPage } from '../../../file-preview/utils/compare-mode.utils';
import { NGXLogger } from 'ngx-logger';
import { LicenseService } from '@services/license.service';
import PDFDoc = Core.PDFNet.PDFDoc;

@Component({
    selector: 'redaction-compare-file-input',
    templateUrl: './compare-file-input.component.html',
    styleUrls: ['./compare-file-input.component.scss'],
})
export class CompareFileInputComponent {
    @ViewChild('input', { static: true }) private readonly _input: ElementRef;

    constructor(
        private readonly _pdf: PdfViewer,
        private readonly _logger: NGXLogger,
        private readonly _loadingService: LoadingService,
        private readonly _documentViewer: REDDocumentViewer,
        private readonly _filesMapService: FilesMapService,
        private readonly _licenseService: LicenseService,
        private readonly _dialogService: SharedDialogService,
        private readonly _viewerHeaderService: ViewerHeaderService,
    ) {}

    get #filename() {
        const { dossierId, fileId } = this._pdf;
        if (!dossierId || !fileId) {
            this._logger.error('No dossier id or file id when uploading compare file!');
            return 'document.pdf';
        }

        return this._filesMapService.get(dossierId, fileId)?.filename ?? 'document.pdf';
    }

    upload(files: FileList) {
        const fileToCompare = files[0];
        this._input.nativeElement.value = null;

        if (!fileToCompare) {
            console.error('No file to compare!');
            return;
        }

        const fileReader = new FileReader();
        fileReader.onload = () => this.#createDocumentsAndCompare(fileReader.result as ArrayBuffer, fileToCompare.name);

        fileReader.readAsArrayBuffer(fileToCompare);
    }

    async #createDocumentsAndCompare(buffer: ArrayBuffer, fileName: string) {
        const currentBlob = await this._documentViewer.blob();
        const pdfNet = this._pdf.PDFNet;

        const compareDocument = await pdfNet.PDFDoc.createFromBuffer(buffer);
        const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await currentBlob.arrayBuffer());

        const currentDocumentPageCount = await currentDocument.getPageCount();
        const compareDocumentPageCount = await compareDocument.getPageCount();

        if (currentDocumentPageCount !== compareDocumentPageCount) {
            const result = await this.#askForConfirmation(fileName, currentDocumentPageCount, compareDocumentPageCount);
            if (result !== ConfirmOptions.CONFIRM) {
                return;
            }
        }

        this._documentViewer.close();
        await this.#loadCompareDocument(currentDocument, compareDocument);
    }

    #askForConfirmation(fileName: string, currentDocumentPageCount: number, compareDocumentPageCount: number) {
        const ref: MatDialogRef<unknown, ConfirmOption> = this._dialogService.openDialog('confirm', {
            title: _('confirmation-dialog.compare-file.title'),
            question: _('confirmation-dialog.compare-file.question'),
            translateParams: {
                fileName,
                currentDocumentPageCount,
                compareDocumentPageCount,
            },
        } as IConfirmationDialogData);

        return firstValueFrom(ref.afterClosed());
    }

    async #loadCompareDocument(current: PDFDoc, compare: PDFDoc) {
        this._loadingService.start();
        await this.#mergeDocuments(current, compare);
        this._viewerHeaderService.disable([HeaderElements.COMPARE_BUTTON]);
        this._viewerHeaderService.enable([HeaderElements.CLOSE_COMPARE_BUTTON]);
        this._loadingService.stop();
    }

    async #mergeDocuments(current: PDFDoc, compare: PDFDoc) {
        const pdfNet = this._pdf.PDFNet;
        const merged = await pdfNet.PDFDoc.create();

        try {
            const maxPageCount = Math.max(await current.getPageCount(), await compare.getPageCount());

            for (let idx = 1; idx <= maxPageCount; idx++) {
                await processPage(idx, current, compare, merged, pdfNet, this._licenseService.activeLicenseKey);
                await processPage(idx, compare, current, merged, pdfNet, this._licenseService.activeLicenseKey);
            }

            const buffer = await merged.saveMemoryBuffer(pdfNet.SDFDoc.SaveOptions.e_linearized);

            const mergedDocumentBuffer = new Blob([buffer], {
                type: 'application/pdf',
            });

            this._pdf.openCompareMode();

            this._pdf.instance.UI.loadDocument(mergedDocumentBuffer, {
                filename: this.#filename,
            });

            this._pdf.navigateTo(1);
        } catch (e) {
            console.error(e);
        }
    }
}
