const ESCALA_CANVAS = 4;

/**
 * Classe para o UC de carimbo do PDFJS.
 */
class GOVBRCarimboUC {
    /**
     * @type {import("./GOVBRPDFJSUserControl.mjs").GOVBRCarimboUserControl}
     */
    userControl;
    /**
     * @type {HTMLElement}
     */
    host;

    /**
     * @type {ShadowRoot}
     */
    __govbr_carimbo_shadow;
    /**
     * @type {HTMLCanvasElement}
     */
    __govbr_carimbo_canvas;

    /**
     * @param {import("./GOVBRPDFJSUserControl.mjs").GOVBRCarimboUserControl} userControl
     */
    constructor(userControl) {
        this.userControl = userControl;
    }

    /**
     * Inicia o componente.
     * @param {HTMLElement} host
     */
    async init(host) {
        const botao = /** @type {HTMLButtonElement} */ (host.querySelector('.govbr-pdf-carimbo-posicionar-btn'));
        if (botao) {
            botao.disabled = true;
        }

        const containerCarimbo = document.createElement('div');
        containerCarimbo.classList.add('govbr-pdf-carimbo-preview');
        this.host = host;
        this.host.append(containerCarimbo);
        const titulo = /** @type {HTMLElement} */ (this.host.querySelector('.govbr-pdf-carimbo-posicionar-lbl'));
        if (titulo) {
            titulo.innerText = this.userControl.LABEL_TITULO || '';
            if (this.userControl.LABEL_TITULO) {
                titulo.style.display = '';
            } else {
                titulo.style.display = 'none';
            }
        }
        await GOVBRPlataformaJS.importarStyleSheet(this.userControl.URL_CDN, 'pdfjs', this.userControl.VERSAO_JS_COMPONENTE, 'GOVBRCarimboUC', host);

        this.__govbr_carimbo_shadow = containerCarimbo.attachShadow({ mode: 'closed' });
        if (this.userControl.HTML_CARIMBO) {
            const frameConteudo = document.createElement('iframe');
            const load = new Promise((resolve) => frameConteudo.addEventListener('load', () => resolve()));
            frameConteudo.src = 'about:blank';
            this.__govbr_carimbo_shadow.append(frameConteudo);
            await load;
            frameConteudo.contentDocument.body.innerHTML = '<span style="display: block;width: fit-content;">' + this.userControl.HTML_CARIMBO + '</span>';

            GOVBRPlataformaJS.bloqueiaElemento(this.host);
            // Espera as imagens carregarem.
            const promisesImg = Promise.all([
                ...Array.from(frameConteudo.contentDocument.body.querySelectorAll('img'), (img) => {
                    img.setAttribute('crossorigin', 'anonymous');
                    return new Promise((resolve) => {
                        img.addEventListener('load', () => resolve());
                        img.addEventListener('error', () => resolve());
                    });
                }),
                Promise.resolve(),
            ]);
            // Ainda não carregaram.
            let resolved = false;
            await new Promise((resolve) => {
                const doResolve = () => {
                    if (!resolved) {
                        resolved = true;
                        resolve();
                    }
                };
                // Se passaram 15 segundos, resolve imediatamente para não travar
                setTimeout(doResolve, 15000);
                // Resolve imediatamente.
                promisesImg.then(doResolve);
            });
            // @ts-ignore
            const canvas = await html2canvas(frameConteudo.contentDocument.body.children[0], {
                allowTaint: false,
                useCORS: true,
                logging: false,
                scale: ESCALA_CANVAS,
            });
            this.__govbr_carimbo_shadow.innerHTML = '';
            this.__govbr_carimbo_shadow.append(canvas);
            canvas.style.setProperty('width', (canvas.width / ESCALA_CANVAS) * 1.5 + 'px');
            canvas.style.setProperty('height', (canvas.height / ESCALA_CANVAS) * 1.5 + 'px');
            this.__govbr_carimbo_canvas = canvas;
            this.userControl.DATA_URL_CARIMBO = canvas.toDataURL();

            GOVBRPlataformaJS.desbloqueiaElemento(this.host);
        } else {
            this.__govbr_carimbo_canvas = null;
        }

        if (this.userControl.IDENTIFICADOR_PDFJS) {
            let alvoSeletor = /** @type {Node} */ (document);
            if (this.host && this.host.getRootNode() !== document) {
                alvoSeletor = this.host.getRootNode();
            }
            const componentePDFJS = /** @type {Document} */ (alvoSeletor).querySelector('#' + this.userControl.IDENTIFICADOR_PDFJS);
            if (componentePDFJS) {
                if (botao) {
                    botao.disabled = false;
                    botao.addEventListener('click', (event) => {
                        event.preventDefault();
                        this.userControl.POSICIONA_CARIMBO = !this.userControl.POSICIONA_CARIMBO;
                        this.ativaDesativaCarimbo();
                    });
                }
                this.ativaDesativaCarimbo();
            } else {
                this.userControl.TAMANHO_CARIMBO_X = this.__govbr_carimbo_canvas.width / ESCALA_CANVAS;
                this.userControl.TAMANHO_CARIMBO_Y = this.__govbr_carimbo_canvas.height / ESCALA_CANVAS;
                if (botao) {
                    botao.style.display = 'none';
                }
            }
        } else {
            this.userControl.TAMANHO_CARIMBO_X = this.__govbr_carimbo_canvas.width / ESCALA_CANVAS;
            this.userControl.TAMANHO_CARIMBO_Y = this.__govbr_carimbo_canvas.height / ESCALA_CANVAS;
            if (botao) {
                botao.style.display = 'none';
            }
        }

        GOVBR.logs.debug('PDF - Carimbo iniciado.');
    }

    /**
     * Ativa ou desativa o carimbo
     */
    async ativaDesativaCarimbo() {
        let alvoSeletor = /** @type {Node} */ (document);
        if (this.host && this.host.getRootNode() !== document) {
            alvoSeletor = this.host.getRootNode();
        }
        const componentePDFJS = /** @type {Document} */ (alvoSeletor).querySelector('#' + this.userControl.IDENTIFICADOR_PDFJS);
        if (!componentePDFJS) {
            return;
        }
        await this.aguardaInicializacao(() => {
            const frame = componentePDFJS.querySelector('.govbr-pdfjs-content-frame');
            return frame?.hasAttribute?.('data-carregado-pdfjs');
        });
        /**
         * @type {HTMLIFrameElement}
         */
        const frame = componentePDFJS.querySelector('.govbr-pdfjs-content-frame');
        if (!this.userControl.__govbr_fn_change) {
            this.userControl.__govbr_fn_change = (event) => {
                this.userControl.POSICAO_CARIMBO_X = event.detail.pos.x;
                this.userControl.POSICAO_CARIMBO_Y = event.detail.pos.y;
                this.userControl.TAMANHO_CARIMBO_X = event.detail.tam.x;
                this.userControl.TAMANHO_CARIMBO_Y = event.detail.tam.y;
                this.userControl.PAGINA_CARIMBO = event.detail.pag;
                this.userControl?.posicaoAtualizada?.();
            };
        }
        frame.addEventListener('__govbr_pdfjs_carimbo_change', this.userControl.__govbr_fn_change);

        const botao = this.host.querySelector('.govbr-pdf-carimbo-posicionar-btn');
        if (this.userControl.POSICIONA_CARIMBO) {
            frame.contentWindow?.postMessage?.(
                [
                    '__govbr_pdfjs_exibe_carimbo',
                    frame.getAttribute('data-govbr-id'),
                    {
                        carimboCanvas: this.__govbr_carimbo_canvas
                            ? {
                                  width: this.__govbr_carimbo_canvas.width / ESCALA_CANVAS,
                                  height: this.__govbr_carimbo_canvas.height / ESCALA_CANVAS,
                                  imagem: await new Promise((resolve) => {
                                      this.__govbr_carimbo_canvas.toBlob((blob) => {
                                          resolve(blob);
                                      }, 'image/png');
                                  }),
                                  escala: ESCALA_CANVAS,
                              }
                            : null,
                        posicaoCarimbo: { x: this.userControl.POSICAO_CARIMBO_X, y: this.userControl.POSICAO_CARIMBO_Y },
                        paginaCarimbo: this.userControl.PAGINA_CARIMBO,
                    },
                ],
                '*'
            );
            if (botao) {
                botao.classList.add('govbr-pdf-carimbo-posicionando');
            }
            this.userControl?.posicaoAtualizada?.();
        } else {
            frame.contentWindow?.postMessage?.(
                [
                    '__govbr_pdfjs_oculta_carimbo',
                    frame.getAttribute('data-govbr-id'),
                    {
                        carimboCanvas: this.__govbr_carimbo_canvas
                            ? {
                                  width: this.__govbr_carimbo_canvas.width / ESCALA_CANVAS,
                                  height: this.__govbr_carimbo_canvas.height / ESCALA_CANVAS,
                                  imagem: await new Promise((resolve) => {
                                      this.__govbr_carimbo_canvas.toBlob((blob) => {
                                          resolve(blob);
                                      }, 'image/png');
                                  }),
                                  escala: ESCALA_CANVAS,
                              }
                            : null,
                    },
                ],
                '*'
            );
            if (botao) {
                botao.classList.remove('govbr-pdf-carimbo-posicionando');
            }
            this.userControl?.posicaoAtualizada?.();
        }
    }

    /**
     * @param {() => boolean} fnCondicao
     * @returns {Promise<void>}
     */
    aguardaInicializacao(fnCondicao) {
        /**
         * @param {() => void} resolve
         */
        const fnAguarda = (resolve) => {
            if (fnCondicao()) {
                resolve();
            } else {
                setTimeout(() => fnAguarda(resolve), 1000);
            }
        };
        return new Promise(fnAguarda);
    }
}

// Caso esteja no browser, disponibiliza o widget no objeto de window.
if (typeof window !== 'undefined') {
    // @ts-ignore
    window['GOVBRCarimboUC'] = GOVBRCarimboUC;
}
export { GOVBRCarimboUC };
