import { GOVBREditorPDFUC } from './GOVBREditorPDFUC.mjs';

/**
 * Classe para editores de PDF utilizando do Nutrient.
 */
class GOVBREditorPDFNutrient extends GOVBREditorPDFUC {
    /**
     * @type {Promise<any>}
     */
    instancia;

    async init() {
        GOVBRPlataformaJS.logs.debug('Iniciando Editor de PDF Nutrient/PSPDFKit', this);
        await GOVBRPlataformaJS.importarModulo(new URL('../../pspdfkit-lib/2024.8.0/pspdfkit.js', import.meta.url).toString(), null, null, 'PSPDFKit');
        await GOVBRPlataformaJS.importarStyleSheet(this.userControl.URL_CDN, 'editor-pdf', this.userControl.VERSAO_JS_COMPONENTE, 'GOVBREditorPDFUC', this.host.parentElement);
        if (!GOVBRPlataformaJS.logs.isDevelop && !this.userControl.API_KEY) {
            this.host.innerHTML = `<div class="govbr-editor-pdf-erro-container">
                <div class="govbr-editor-pdf-erro">
                    <i class="govbr-editor-pdf-erro-icone fa-solid fa-exclamation-triangle"></i>
                    <p class="govbr-editor-pdf-erro-titulo">Encontramos uma exceção ao tentar iniciar o componente de editor de PDF.</p>
                    <p class="govbr-editor-pdf-erro-conteudo">A chave de licença não foi encontrada.</p>
                </div>
            </div>`;
            return;
        }
        const config = await this.carregaConfiguracoes();
        this.instancia = new Promise((resolve) => {
            // @ts-ignore
            PSPDFKit.load(config)
                .then(
                    /**
                     * @param {any} instancia
                     */
                    async (instancia) => {
                        const estampas = await this.getEstampas(instancia);
                        instancia.setStampAnnotationTemplates(estampas);
                        resolve(instancia);
                        GOVBRPlataformaJS.logs.debug('Editor de PDF Nutrient/PSPDFKit carregado', instancia);
                    }
                )
                .catch(
                    /**
                     * @param {Error} erro
                     */
                    (erro) => {
                        let message =
                            'O componente retornou a mensagem: <code>' +
                            (erro?.message?.toString?.() || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') +
                            '</code>';
                        if (/invalid license key/i.test(message)) {
                            message = `Chave de licença ${/key expired/.test(message) ? 'expirada' : 'inválida'}.<br/>Caso o problema persista, entre em contato com o administrador.`;
                        }
                        this.host.innerHTML = `<div class="govbr-editor-pdf-erro-container">
                        <div class="govbr-editor-pdf-erro">
                            <i class="govbr-editor-pdf-erro-icone fa-solid fa-exclamation-triangle"></i>
                            <p class="govbr-editor-pdf-erro-titulo">Encontramos uma exceção ao tentar iniciar o componente de editor de PDF.</p>
                            <p class="govbr-editor-pdf-erro-conteudo">${message}</p>
                        </div>
                    </div>`;
                        GOVBRPlataformaJS.logs.error('Erro ao carregar o Editor de PDF Nutrient/PSPDFKit', erro);
                    }
                );
        });
    }

    /**
     * Carrega e retorna as configurações do PSPDFKit
     */
    async carregaConfiguracoes() {
        // @ts-ignore
        const PSPDFKit = window['PSPDFKit'];
        const metaUrl = import.meta.url;
        const baseUrl = new URL('../../pspdfkit-lib/2024.8.0/', metaUrl);
        const cssUrl = new URL('./GOVBREditorPDFInterno.css', metaUrl);
        return {
            licenseKey: this.userControl.API_KEY,
            baseUrl: baseUrl.toString(),
            container: this.host,
            document: this.userControl.URL_PDF,
            theme: PSPDFKit.Theme.LIGHT,
            styleSheets: [
                cssUrl.toString(),
            ],
            locale: 'pt-BR',

            measurementScale: new PSPDFKit.MeasurementScale({
                unitFrom: PSPDFKit.MeasurementScaleUnitFrom.MILIMETERS,
                unitTo: PSPDFKit.MeasurementScaleUnitTo.MILIMETERS,
                fromValue: 1,
                toValue: 1,
            }),

            dateTimeString:
                /**
                 * @param {{dateTime: string, element: HTMLElement}} param0
                 * @returns
                 */
                ({ dateTime, element }) => {
                    if (element === PSPDFKit.UIDateTimeElement.ANNOTATIONS_SIDEBAR) {
                        return new Intl.DateTimeFormat('pt-BR', {
                            dateStyle: 'short',
                            timeStyle: 'short',
                        }).format(new Date(dateTime));
                    } else {
                        return new Intl.DateTimeFormat('pt-BR', {
                            dateStyle: 'full',
                            timeStyle: 'long',
                        }).format(new Date(dateTime));
                    }
                },

            disableForms: this.userControl.DESABILITA_FORMS,
            disableTextSelection: this.userControl.DESABILITA_SELECAO_TEXTO,
            toolbarPlacement: this.userControl.TOOLBAR_INFERIOR ? PSPDFKit.ToolbarPlacement.BOTTOM : PSPDFKit.ToolbarPlacement.TOP,
            toolbarItems: await this.getItensToolbar(),

            instantJSON: this.userControl.ANOTACOES_INSTANT_JSON || undefined,
            XFDF: this.userControl.ANOTACOES_XFDF || undefined,
            XFDFKeepCurrentAnnotations: this.userControl.ANOTACOES_XFDF ? true : undefined,

            initialViewState: this.getViewStateInicial(),
        };
    }

    /**
     * Retorna os itens que compõem a barra de ferramentas.
     */
    async getItensToolbar() {
        // @ts-ignore
        const PSPDFKit = window['PSPDFKit'];
        const toolbarItems = (PSPDFKit.defaultToolbarItems || []).slice();
        const botoes = (this.userControl.BOTOES_TOOLBAR || []).slice();
        if (this.userControl.BOTAO_SALVAR_FORMATO && this.userControl.BOTAO_SALVAR_FORMATO !== 'NAO_SALVA') {
            botoes.push({
                id: '__govbr_download',
                idIconeFA: 'floppy-disk',
                formatoIconeFA: 'solid',
                titulo: 'Salvar',
                tipo: 'custom',
            });
        }

        if (this.userControl.API_KEY) {
            toolbarItems.push({ type: 'measure' });
        }

        (
            await Promise.all(
                botoes.map(async (botao) => {
                    let svgIcone;
                    try {
                        const url = new URL('../../imgs/fa/6.7.1/fa-' + botao.formatoIconeFA + '.svg', import.meta.url);
                        const svg = await (await fetch(url)).text();
                        const parser = new DOMParser();
                        const root = parser.parseFromString(svg, 'application/xml');
                        const icone = root.querySelector('#' + botao.idIconeFA);
                        const conteudoIcone = icone?.innerHTML || '';
                        let viewBox = icone?.getAttribute?.('viewBox') || '0 0 0 0';
                        const partesViewBox = viewBox.split(' ').map((e) => parseFloat(e));
                        viewBox = [
                            (partesViewBox[0] || 0) - 15,
                            (partesViewBox[1] || 0) - 15,
                            (partesViewBox[2] || 0) + 15,
                            (partesViewBox[3] || 0) + 15,
                        ].join(' ');

                        svgIcone =
                            '<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24" class="govbr-icone-botao-custom govbr-icone-botao-custom-' +
                            botao.idIconeFA +
                            ' govbr-icone-botao-custom-' +
                            botao.formatoIconeFA +
                            '" viewBox="' +
                            viewBox +
                            '">' +
                            conteudoIcone +
                            '</svg>';
                    } catch (ex) {
                        GOVBRPlataformaJS.logs.fatal(ex);
                        svgIcone = '';
                    }
                    return {
                        type: botao.tipo,
                        id: botao.id,
                        dropdownGroup: botao.idGrupoDropdown,
                        icon: svgIcone,
                        mediaQueries: botao.mediaQueriesVisibilidade,
                        responsiveGroup: botao.idGrupoResponsivo,
                        title: botao.titulo,
                        onPress: () => {
                            this.disparaClickBotaoToolbar(botao.id);
                        },
                    };
                })
            )
        ).forEach((e) => toolbarItems.push(e));

        return toolbarItems;
    }

    /**
     * Dispara o evento de clicar em um botao da toolbar.
     * @param {string} idBotao
     */
    disparaClickBotaoToolbar(idBotao) {
        if (idBotao === '__govbr_download') {
            switch (this.userControl.BOTAO_SALVAR_FORMATO) {
                case 'SALVA_JSON':
                    this.exportaInstantJSON();
                    break;
                case 'SALVA_XFDF':
                    this.exportaXFDF();
                    break;
                case 'SALVA_PDF':
                    this.exportaPDF();
                    break;
                case 'SALVA_OFFICE':
                    this.exportaOffice();
                    break;
            }
        } else {
            this.userControl.ID_BOTAO_CLICADO = idBotao;
            this.userControl.onClickBotaoToolbar?.();
        }
    }

    /**
     * Traz a lista de estampas customizadas.
     * @param {any} instancia
     */
    async getEstampas(instancia) {
        // @ts-ignore
        const PSPDFKit = window['PSPDFKit'];
        const templates = (PSPDFKit.defaultStampAnnotationTemplates || []).slice();
        await Promise.all(
            (this.userControl.ESTAMPAS_CUSTOMIZADAS || []).map(async (estampa) => {
                if (estampa.tipo === 'imagem') {
                    const request = await fetch(estampa.url);
                    const blob = await request.blob();
                    const imageAttachmentId = await instancia.createAttachment(blob);
                    templates.push(
                        new PSPDFKit.Annotations.ImageAnnotation({
                            contentType: estampa.formato,
                            imageAttachmentId,
                            description: estampa.descricao,
                            customData: {
                                idEstampa: estampa.id,
                            },

                            boundingBox: new PSPDFKit.Geometry.Rect({
                                left: 0,
                                top: 0,
                                width: estampa.largura,
                                height: estampa.altura,
                            }),
                        })
                    );
                } else {
                    templates.push(
                        new PSPDFKit.Annotations.StampAnnotation({
                            stampType: 'Custom',
                            title: estampa.texto,
                            subtitle: estampa.subtitulo,
                            color: estampa.usaCor && estampa.cor ? new PSPDFKit.Color({ r: estampa.cor.vermelho, g: estampa.cor.verde, b: estampa.cor.azul }) : null,
                            customData: {
                                idEstampa: estampa.id,
                            },

                            boundingBox: new PSPDFKit.Geometry.Rect({
                                left: 0,
                                top: 0,
                                width: estampa.largura,
                                height: estampa.altura,
                            }),
                        })
                    );
                }
            })
        );
        return templates;
    }

    /**
     * Retorna o ViewState inicial que controla a apresentação visual do PSPDFKit na inicialização.
     */
    getViewStateInicial() {
        // @ts-ignore
        const PSPDFKit = window['PSPDFKit'];
        return new PSPDFKit.ViewState({
            allowExport: this.userControl.PERMITE_DOWNLOAD,
            allowPrinting: this.userControl.PERMITE_IMPRIMIR,
            currentPageIndex: this.userControl.PAGINA_INICIAL || 0,
            enableAnnotationToolbar: this.userControl.PERMITE_ANOTACOES,
            layoutMode: PSPDFKit.LayoutMode.AUTO,
            readOnly: !this.userControl.PERMITE_ANOTACOES,
            scrollMode: PSPDFKit.ScrollMode.CONTINUOUS,
            showToolbar: this.userControl.EXIBE_TOOLBAR,
            sidebarMode: this.userControl.SIDEBAR_ABERTA ? PSPDFKit.SidebarMode.THUMBNAILS : null,
            sidebarPlacement: this.userControl.SIDEBAR_DIREITA ? PSPDFKit.SidebarPlacement.END : PSPDFKit.SidebarPlacement.START,
            sidebarWidth: this.userControl.LARGURA_SIDEBAR || 0,
            pagesRotation: 0,
            pageSpacing: 12,
            zoom: this.userControl.NIVEL_ZOOM || PSPDFKit.ZoomMode.AUTO,
            zoomStep: this.userControl.ETAPAS_ZOOM || null,
        });
    }

    async exportaInstantJSON() {
        GOVBRPlataformaJS.bloqueiaElemento(this.host.parentElement);
        const json = await (await this.instancia).exportInstantJSON();
        this.userControl.RESULTADO_INSTANT_JSON = JSON.stringify(json);
        this.userControl?.exportaInstantJSONPronto?.();
        GOVBRPlataformaJS.desbloqueiaElemento(this.host.parentElement);
    }

    async exportaXFDF() {
        GOVBRPlataformaJS.bloqueiaElemento(this.host.parentElement);
        const xfdf = await (await this.instancia).exportXFDF();
        this.userControl.RESULTADO_XFDF = xfdf;
        this.userControl?.exportaXFDFPronto?.();
        GOVBRPlataformaJS.desbloqueiaElemento(this.host.parentElement);
    }

    async exportaPDF() {
        GOVBRPlataformaJS.bloqueiaElemento(this.host.parentElement);
        /**
         * @type {{flatten: string, incremental: boolean}|{conformance: string, vectorization: boolean, rasterization: boolean}}
         */
        let configExporta = { flatten: this.userControl.EXPORTA_PDF_FLATTEN, incremental: false };
        if (this.userControl.EXPORTA_PDF_FORMATO && this.userControl.EXPORTA_PDF_FORMATO !== 'PDF') {
            configExporta = {
                conformance: this.userControl.EXPORTA_PDF_FORMATO,
                vectorization: true,
                rasterization: true,
            };
        }
        /**
         * @type {ArrayBuffer}
         */
        const pdf = await (await this.instancia).exportPDF(configExporta);
        let binary = '';
        let bytes = new Uint8Array(pdf);
        let len = bytes.byteLength;
        for (let i = 0; i < len; i++) {
            binary += String.fromCharCode(bytes[i]);
        }
        this.userControl.RESULTADO_PDF = window.btoa(binary);
        this.userControl?.exportaPDFPronto?.();
        GOVBRPlataformaJS.desbloqueiaElemento(this.host.parentElement);
    }

    async exportaOffice() {
        GOVBRPlataformaJS.bloqueiaElemento(this.host.parentElement);
        let configExporta = { format: this.userControl.FORMATO_OFFICE || 'docx' };
        /**
         * @type {ArrayBuffer}
         */
        const doc = await (await this.instancia).exportOffice(configExporta);
        let binary = '';
        let bytes = new Uint8Array(doc);
        let len = bytes.byteLength;
        for (let i = 0; i < len; i++) {
            binary += String.fromCharCode(bytes[i]);
        }
        this.userControl.RESULTADO_OFFICE = window.btoa(binary);
        this.userControl?.exportaOfficePronto?.();
        GOVBRPlataformaJS.desbloqueiaElemento(this.host.parentElement);
    }

    async imprimir() {
        (await this.instancia).print();
    }
}
export { GOVBREditorPDFNutrient };
