import { GOVBRFormsUC } from './GOVBRFormsUC.mjs';
import { GOVBRFormsUCComponente, GOVBRFormsUCComponenteContainer, GOVBRFormsUCComponenteInput } from './GOVBRFormsUCComponente.mjs';

// *****************
// **** EVENTOS ****
// *****************

/**
 * Representa um retorno válido para uma condicionante de evento.
 * @typedef {GOVBRFormsUCEventoOperacao[]} GOVBRFormsUCEventoRetorno
 */

/**
 * Representa um evento a ser disparado.
 * @typedef {Object} GOVBRFormsUCEvento
 * @prop {string} Tipo - Tipo do evento, identificador, exemplo, onLoad.
 * @prop {GOVBRFormsUCCondicionante<GOVBRFormsUCEventoRetorno>[]} Condicionantes - Condicionantes a serem aplicadas. Cada uma será validada na ordem, na estrutura de um "Se-Senão", será executada a primeira que for válida.
 */

// ********************
// **** VALIDAÇÕES ****
// ********************

/**
 * Indica o resultado de uma validação, true se é válida, false se não é, e uma string se não é e deve exibir uma mensagem própria.
 * @typedef {Object} GOVBRFormsUCValidacaoResultado
 * @prop {boolean} Retorno
 * @prop {string} Mensagem
 */

/**
 * Representa uma validação a ser realizada.
 * @typedef {Object} GOVBRFormsUCValidacao
 * @prop {GOVBRFormsUCCondicionante<GOVBRFormsUCValidacaoResultado>[]} Condicionantes - Condicionantes a serem aplicadas. Cada uma será validada na ordem, será executada a primeira que for válida.
 */

// ***********************
// **** CONDICIONANTE ****
// ***********************

/**
 * Operadores possíveis para agregação de condicionais em agregação.
 * @typedef {'e'|'ou'} GOVBRFormsUCCondicionanteOperadorAgregacao
 */

/**
 * Representa uma condicionante, um aglomerado de condicionais que gera um resultado.
 * @template {any} T
 * @typedef {Object} GOVBRFormsUCCondicionante
 * @prop {GOVBRFormsUCCondicionanteCondicionalAgregada|GOVBRFormsUCCondicionanteCondicional} Condicional - Agregação de condicionais a serem aplicados para satisfazer a condicionante.
 * @prop {T} Resultado
 */

/**
 * Representa duas condicionais agrupadas sobre um mesmo agregador
 * @typedef {Object} GOVBRFormsUCCondicionanteCondicionalAgregada
 * @prop {true} Agregada
 * @prop {(GOVBRFormsUCCondicionanteCondicional|GOVBRFormsUCCondicionanteCondicionalAgregada)[]} Condicionais
 * @prop {GOVBRFormsUCCondicionanteOperadorAgregacao} Operador
 */

/** @typedef {'igual'|'diferente'|'maior-que'|'menor-que'|'maior-igual'|'menor-igual'|'entre'} GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresNumero */
/** @typedef {'igual'|'diferente'|'maior-que'|'menor-que'|'maior-igual'|'menor-igual'|'entre'} GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresData */
/** @typedef {'igual'|'diferente'|'contem'|'nao-contem'|'inicia-com'|'termina-com'|'expressao-regular'} GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresTexto */
/** @typedef {'igual'|'diferente'|'contem'|'nao-contem'} GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresLista */
/** @typedef {'igual'|'diferente'} GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresBooleano */
/** @typedef {'nulo'|'nao-nulo'} GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresGlobais */

/**
 * Operadores válidos para as condicionantes.
 * @typedef {GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresNumero|
 *           GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresData|
 *           GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresTexto|
 *           GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresLista|
 *           GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresBooleano|
 *           GOVBRFormsUCCondicionanteCondicionalOperadoresOperadoresGlobais} GOVBRFormsUCCondicionanteCondicionalOperadores
 */

/**
 * @typedef {Object} GOVBRFormsUCCondicionanteCondicional
 * @prop {false} Agregada
 * @prop {[GOVBRFormsUCAlvo, GOVBRFormsUCAlvo, GOVBRFormsUCAlvo]} ValoresCondicao - Valores para a condição.
 * @prop {GOVBRFormsUCCondicionanteCondicionalOperadores} Operador - Operador a ser aplicado sobre as condicionais, varia com base no tipo do primeiro alvo. Pode alterar os valores possíveis para outros alvos.
 */

// *******************
// **** ALVOS ****
// *******************

/**
 * Indica que o alvo de uma operação ou condicionante é global
 * @typedef {Object} GOVBRFormsUCAlvoGlobal
 * @prop {'global'} Tipo - Indica que o alvo é um componente.
 * @prop {null=} Id
 * @prop {null=} Valor
 */

/**
 * Indica que o alvo de uma operação ou condicionante é um componente.
 * @typedef {Object} GOVBRFormsUCAlvoIndefinido
 * @prop {null} Tipo - Indica que o alvo não foi definido.
 * @prop {null=} Id
 * @prop {null=} Valor
 */

/**
 * Indica que o alvo de uma operação ou condicionante é um componente.
 * @typedef {Object} GOVBRFormsUCAlvoComponente
 * @prop {'componente'} Tipo - Indica que o alvo é um componente.
 * @prop {string} Id - Identificador do componente. O tipo do componente influencia na possibilidade de valores passados para operações ou condicionantes.
 * @prop {null=} Valor
 */

/**
 * Indica que o alvo de uma operação ou condicionante é a representação textual de um valor.
 * @typedef {Object} GOVBRFormsUCAlvoValor
 * @prop {'valor'} Tipo - Indica que o alvo é um valor.
 * @prop {null=} Id
 * @prop {string} Valor - Valor a ser utilizado como parâmetro da operação ou como comparativo da condicionante.
 */

/**
 * Indica o alvo de uma operação.
 * @typedef {GOVBRFormsUCAlvoComponente|GOVBRFormsUCAlvoValor|GOVBRFormsUCAlvoIndefinido} GOVBRFormsUCAlvo
 */

// *******************
// **** OPERAÇÕES ****
// *******************

/**
 * Operações possíveis a serem aplicadas em campos.
 * @typedef {GOVBRFormsUCOperacaoComponente|'obrigatorio'|'leitura'} GOVBRFormsUCOperacaoCampo
 */

/**
 * Operações possíveis a serem aplicadas em componentes.
 * @typedef {GOVBRFormsUCOperacaoGlobal|'ativa'} GOVBRFormsUCOperacaoAba
 */

/**
 * Operações possíveis a serem aplicadas em componentes.
 * @typedef {GOVBRFormsUCOperacaoGlobal|'visivel'} GOVBRFormsUCOperacaoComponente
 */

/**
 * Operações possíveis a serem aplicadas globalmente.
 * @typedef {'mensagem'} GOVBRFormsUCOperacaoGlobal
 */

/**
 * Indica uma operação qualquer, as possibilidades de valores desta podem mudar com o tipo do alvo.
 * @typedef {GOVBRFormsUCOperacaoGlobal|GOVBRFormsUCOperacaoComponente|GOVBRFormsUCOperacaoCampo|GOVBRFormsUCOperacaoAba} GOVBRFormsUCOperacao
 */

/**
 * Indica uma operação completa de um evento que consiste a aplicar "operacao" sobre "alvo" com o "valorOperacao" se aplicável.
 * @typedef {Object} GOVBRFormsUCEventoOperacao
 * @prop {GOVBRFormsUCAlvoComponente|GOVBRFormsUCAlvoGlobal|GOVBRFormsUCAlvoIndefinido} Alvo - Alvo que irá receber a operação.
 * @prop {GOVBRFormsUCOperacao} Operacao - Operação que será aplicada com o alvo, valores podem mudar com base no tipo do componente alvo.
 * @prop {GOVBRFormsUCAlvo} ValorOperacao - Valor que será utilizado para aplicar.
 *     Caso seja um componente, será utilizado o valor do componente, somente podem ser selecionados componentes de campos com tipos válidos para a operação.
 */

export class GOVBRFormsUCConfiguradorEventos {
    prefixoRetorno;
    descricaoItem;
    descricaoNovo;

    /**
     * @type {GOVBRFormsUC}
     */
    form;
    /**
     * @type {string}
     */
    identificadorAlvo;
    /**
     * @type {HTMLDivElement}
     */
    containerItens;
    /**
     * @type {(GOVBRFormsUCValidacao|GOVBRFormsUCEvento)[]}
     */
    itens;
    /**
     * @type {(el: HTMLElement, val: GOVBRFormsUCCondicionante<GOVBRFormsUCValidacaoResultado|GOVBRFormsUCEventoRetorno>) => HTMLElement}
     */
    fnMontaRetorno;
    /**
     * @type {string[]}
     */
    contexto;
    /**
     * @type {GOVBRFormsUCValidacaoResultado|GOVBRFormsUCEventoRetorno}
     */
    resultadoPadrao;
    /**
     * @type {boolean}
     */
    condicionalObrigatoria;

    /**
     * @type {HTMLElement}
     */
    itemFoco;

    /**
     * @param {string} prefixoRetorno
     * @param {string} descricaoItem
     * @param {string} descricaoNovo
     */
    constructor(prefixoRetorno, descricaoItem, descricaoNovo) {
        this.prefixoRetorno = prefixoRetorno;
        this.descricaoItem = descricaoItem;
        this.descricaoNovo = descricaoNovo;
    }

    // *****************
    // **** EVENTOS ****
    // *****************

    /**
     * Abre a janela para o Usuário realizar a configuração dos eventos de um item.
     * @param {GOVBRFormsUC} form
     * @param {string} nomeAlvo
     * @param {GOVBRFormsUCEvento[]} eventos
     * @param {[string, string, string][]} eventosValidos
     * @param {(resultado:GOVBRFormsUCEvento[]) => void} fnConfirma
     * @param {string} identificadorAlvo
     * @param {string[]} contexto
     */
    static abreJanelaConfiguracaoEventos(form, nomeAlvo, eventos, eventosValidos, fnConfirma, identificadorAlvo = null, contexto = []) {
        if (!eventos) {
            throw new Error('Falha ao carregar os eventos, entre em contato com o suporte.');
        }
        eventos = JSON.parse(JSON.stringify(eventos));
        const dialog = form.abreDialog(
            'Configurar Eventos - ' + nomeAlvo,
            () => {
                fnConfirma(listasEventos.flat());
            },
            () => {
                configurador.classList.add('govbr-forms-configurador-confirmou');
                return Array.from(dialog.querySelectorAll('input,select,textarea')).every(
                    /** @param {HTMLInputElement} input */ (input) => {
                        if (!input.checkVisibility()) {
                            return true;
                        }
                        const valid = input.checkValidity();
                        if (!valid) {
                            input.reportValidity();
                        }
                        return valid;
                    }
                );
            }
        );
        /**
         * @type {GOVBRFormsUCEvento[][]}
         */
        const listasEventos = [];
        const configurador = document.createElement('div');
        configurador.classList.add('govbr-forms-configurador');
        configurador.classList.add('govbr-forms-configurador-eventos');
        eventosValidos.forEach(([nome, descricao, hint]) => {
            const self = new GOVBRFormsUCConfiguradorEventos('Faça', 'Evento', 'Novo');
            self.form = form;
            self.identificadorAlvo = identificadorAlvo;
            self.resultadoPadrao = [
                {
                    Alvo: {
                        Tipo: null,
                    },
                    Operacao: null,
                    ValorOperacao: {
                        Tipo: null,
                    },
                },
            ];
            self.condicionalObrigatoria = false;
            const fieldsetEvento = document.createElement('fieldset');
            fieldsetEvento.classList.add('govbr-forms-configurador-evento');
            const titulo = document.createElement('legend');
            titulo.innerText = descricao;
            fieldsetEvento.append(titulo);
            const subtitulo = document.createElement('sub');
            subtitulo.classList.add('govbr-forms-configurador-evento-subtitulo');
            subtitulo.innerText = hint;
            fieldsetEvento.append(subtitulo);
            const eventosItem = eventos.filter((evento) => evento.Tipo === nome);
            listasEventos.push(eventosItem);
            self.montaItensCondicionantes(fieldsetEvento, eventosItem, contexto, self.criaNovoEvento.bind(self, nome), self.criaConfiguracaoRetornoEvento.bind(self));
            configurador.append(fieldsetEvento);
        });
        dialog.append(configurador);
    }

    /**
     * Cria uma nova instância de validações.
     * @param {string} tipo
     * @returns {GOVBRFormsUCEvento}
     */
    criaNovoEvento(tipo) {
        return {
            Tipo: tipo,
            Condicionantes: this.montaCondicionantesPadrao(),
        };
    }

    /**
     * Cria uma nova instância de validações.
     * @param {HTMLElement} container
     * @param {GOVBRFormsUCCondicionante<GOVBRFormsUCEventoRetorno>} condicionante
     */
    criaConfiguracaoRetornoEvento(container, condicionante) {
        const recriaResultado = () => {
            container.innerHTML = '';
            condicionante.Resultado.forEach((resultado, idx) => {
                const item = document.createElement('div');
                item.classList.add('govbr-forms-configurador-item-resultado-container');
                this.criaConteudoSecaoConfiguracaoRetornoEvento(item, resultado);
                container.append(item);

                if (condicionante.Resultado.length > 1) {
                    const btnRemover = document.createElement('button');
                    btnRemover.classList.add('govbr-forms-configurador-botao');
                    btnRemover.classList.add('govbr-forms-configurador-botao-remover-resultado');
                    btnRemover.title = 'Remover Operação';
                    const iconeRemover = document.createElement('i');
                    iconeRemover.classList.add('fa-solid');
                    iconeRemover.classList.add('fa-trash-can');
                    btnRemover.append(iconeRemover);
                    btnRemover.addEventListener('click', () => {
                        condicionante.Resultado.splice(idx, 1);
                        recriaResultado();
                    });
                    item.append(btnRemover);
                }

                const btnAdicionar = document.createElement('button');
                btnAdicionar.classList.add('govbr-forms-configurador-botao');
                btnAdicionar.classList.add('govbr-forms-configurador-botao-novo-resultado');
                btnAdicionar.title = 'Adicionar Nova Operação';
                const iconeAdicionarNovo = document.createElement('i');
                iconeAdicionarNovo.classList.add('fa-solid');
                iconeAdicionarNovo.classList.add('fa-plus');
                btnAdicionar.append(iconeAdicionarNovo);
                btnAdicionar.addEventListener('click', () => {
                    condicionante.Resultado.splice(idx + 1, 0, {
                        Alvo: {
                            Tipo: null,
                        },
                        Operacao: null,
                        ValorOperacao: {
                            Tipo: null,
                        },
                    });
                    recriaResultado();
                });
                item.append(btnAdicionar);
            });
        };
        recriaResultado();
    }

    /**
     * @param {HTMLElement} container
     * @param {GOVBRFormsUCEventoOperacao} resultado
     */
    criaConteudoSecaoConfiguracaoRetornoEvento(container, resultado) {
        const fnChangeOperacao = () => {
            inputTextoMensagem.style.setProperty('display', 'none');
            inputAlvo.style.setProperty('display', 'none');
            inputOperacaoComponente.style.setProperty('display', 'none');
            switch (inputOperacao.value) {
                case 'elemento':
                    inputAlvo.style.setProperty('display', '');
                    inputOperacaoComponente.style.setProperty('display', '');
                    break;
                case 'mensagem':
                    inputTextoMensagem.style.setProperty('display', '');
                    break;
            }
        };

        const fnChangeInputAlvo = () => {
            inputOperacaoComponente.innerHTML = '';
            inputOperacaoComponente.append(this.criaOpcaoSelectLista('', 'Selecione...'));
            if (inputAlvo.value) {
                inputOperacaoComponente.disabled = false;
                inputOperacaoComponente.append(this.criaOpcaoSelectLista('visivel_0', 'como oculto'));
                inputOperacaoComponente.append(this.criaOpcaoSelectLista('visivel_1', 'como visível'));
                const alvoComponente = campos[inputAlvo.value];
                if (alvoComponente.tipo === 'input') {
                    inputOperacaoComponente.append(this.criaOpcaoSelectLista('obrigatorio_0', 'como opcional'));
                    inputOperacaoComponente.append(this.criaOpcaoSelectLista('obrigatorio_1', 'como obrigatório'));
                    inputOperacaoComponente.append(this.criaOpcaoSelectLista('leitura_1', 'como somente leitura'));
                    inputOperacaoComponente.append(this.criaOpcaoSelectLista('leitura_0', 'como editável'));
                } else if (alvoComponente.tipo == 'tabs') {
                    inputOperacaoComponente.append(this.criaOpcaoSelectLista('ativa_1', 'como ativa'));
                }
            } else {
                inputOperacaoComponente.disabled = true;
                inputOperacaoComponente.value = '';
            }
        };

        const campos = this.getCamposDisponiveis(false, true);

        const inputOperacao = document.createElement('select');
        inputOperacao.classList.add('govbr-forms-configurador-item-campo');
        inputOperacao.title = 'Operação';
        inputOperacao.append(this.criaOpcaoSelectLista('', 'Nada'));
        inputOperacao.append(this.criaOpcaoSelectLista('mensagem', 'Exiba a Mensagem'));
        inputOperacao.append(this.criaOpcaoSelectLista('elemento', 'Defina o elemento'));
        inputOperacao.addEventListener('change', () => {
            fnChangeOperacao();
            inputTextoMensagem.value = '';
            inputAlvo.value = '';
            inputOperacaoComponente.value = '';
            if (inputOperacao.value !== 'elemento') {
                resultado.Operacao = /** @type {GOVBRFormsUCOperacao} */ (inputOperacao.value === '' ? null : inputOperacao.value);
                resultado.Alvo = {
                    Tipo: 'global',
                };
            } else {
                resultado.Operacao = null;
            }
            resultado.ValorOperacao = {
                Tipo: null,
            };
        });
        container.append(inputOperacao);

        const inputTextoMensagem = document.createElement('textarea');
        inputTextoMensagem.classList.add('govbr-forms-configurador-item-campo');
        inputTextoMensagem.title = 'Mensagem';
        inputTextoMensagem.required = true;
        inputTextoMensagem.addEventListener('change', () => {
            resultado.ValorOperacao = {
                Tipo: 'valor',
                Valor: inputTextoMensagem.value,
            };
        });
        container.append(inputTextoMensagem);

        const inputAlvo = document.createElement('select');
        inputAlvo.classList.add('govbr-forms-configurador-item-campo');
        inputAlvo.title = 'Componente Alvo';
        inputAlvo.required = true;
        inputAlvo.append(this.criaOpcaoSelectLista('', 'Selecione...'));
        Object.values(campos).forEach((componente) => {
            inputAlvo.append(this.criaOpcaoSelectLista(componente.identificador, componente.dataIdentificador + ' (' + componente.titulo + ')'));
        });
        inputAlvo.addEventListener('change', () => {
            fnChangeInputAlvo();
            inputOperacaoComponente.value = '';
            if (inputAlvo.value) {
                resultado.Alvo = {
                    Tipo: 'componente',
                    Id: inputAlvo.value,
                };
            } else {
                resultado.Alvo = { Tipo: null };
            }
        });
        container.append(inputAlvo);

        const inputOperacaoComponente = document.createElement('select');
        inputOperacaoComponente.classList.add('govbr-forms-configurador-item-campo');
        inputOperacaoComponente.title = 'Campo Alvo';
        inputOperacaoComponente.required = true;
        inputOperacaoComponente.disabled = true;
        inputOperacaoComponente.addEventListener('change', () => {
            if (inputOperacaoComponente.value) {
                const [operacao, valor] = inputOperacaoComponente.value.split('_');
                resultado.Operacao = /** @type {GOVBRFormsUCOperacao} */ (operacao);
                resultado.ValorOperacao = {
                    Tipo: 'valor',
                    Valor: valor,
                };
            } else {
                resultado.Operacao = null;
            }
        });
        container.append(inputOperacaoComponente);

        if (resultado.Operacao) {
            if (resultado.Alvo.Tipo === 'global') {
                inputOperacao.value = resultado.Operacao;
            } else {
                inputOperacao.value = 'elemento';
            }
        } else {
            inputOperacao.value = '';
        }
        fnChangeOperacao();
        inputTextoMensagem.value = resultado.ValorOperacao.Valor || '';
        if (resultado.Operacao && resultado.Alvo.Tipo === 'componente') {
            inputAlvo.value = resultado.Alvo.Id || '';
        }
        inputAlvo.value = resultado.Alvo.Id || '';
        fnChangeInputAlvo();
        if (resultado.Operacao && resultado.Alvo.Tipo === 'componente') {
            inputOperacaoComponente.value = resultado.Operacao + '_' + resultado.ValorOperacao.Valor;
        }
    }

    // ********************
    // **** VALIDAÇÕES ****
    // ********************

    /**
     * Abre a janela para o Usuário realizar a configuração das validações de um item.
     * @param {GOVBRFormsUC} form
     * @param {string} nomeAlvo
     * @param {GOVBRFormsUCValidacao[]} validacoes
     * @param {(resultado:GOVBRFormsUCValidacao[]) => void} fnConfirma
     * @param {string} identificadorAlvo
     * @param {string[]} contexto
     */
    static abreJanelaConfiguracaoValidacoes(form, nomeAlvo, validacoes, fnConfirma, identificadorAlvo = null, contexto = []) {
        if (!validacoes) {
            throw new Error('Falha ao carregar as validacoes, entre em contato com o suporte.');
        }
        validacoes = JSON.parse(JSON.stringify(validacoes));
        const self = new GOVBRFormsUCConfiguradorEventos('Retorne', 'Validação', 'Nova');
        self.form = form;
        self.identificadorAlvo = identificadorAlvo;
        self.resultadoPadrao = {
            Retorno: true,
            Mensagem: '',
        };
        self.condicionalObrigatoria = true;
        const dialog = form.abreDialog(
            'Configurar Validações - ' + nomeAlvo,
            () => {
                fnConfirma(validacoes);
            },
            () => {
                return Array.from(dialog.querySelectorAll('input,select,textarea')).every(
                    /** @param {HTMLInputElement} input */ (input) => {
                        const valid = input.checkValidity();
                        if (!valid) {
                            input.reportValidity();
                        }
                        return valid;
                    }
                );
            }
        );
        const configurador = document.createElement('div');
        configurador.classList.add('govbr-forms-configurador');
        configurador.classList.add('govbr-forms-configurador-validacoes');
        self.montaItensCondicionantes(configurador, validacoes, contexto, self.criaNovaValidacao.bind(self), self.criaConfiguracaoRetornoValidacao.bind(self));
        dialog.append(configurador);
    }

    /**
     * Cria uma nova instância de validações.
     * @returns {GOVBRFormsUCValidacao}
     */
    criaNovaValidacao() {
        return {
            Condicionantes: this.montaCondicionantesPadrao(),
        };
    }

    /**
     * Cria uma nova instância de validações.
     * @param {HTMLElement} container
     * @param {GOVBRFormsUCCondicionante<GOVBRFormsUCValidacaoResultado>} condicionante
     */
    criaConfiguracaoRetornoValidacao(container, condicionante) {
        const inputValido = document.createElement('select');
        inputValido.classList.add('govbr-forms-configurador-item-campo');
        inputValido.title = 'Retorno da Validação';
        inputValido.append(this.criaOpcaoSelectLista('', 'Inválido'));
        inputValido.append(this.criaOpcaoSelectLista('1', 'Válido'));
        inputValido.value = condicionante.Resultado.Retorno ? '1' : '';
        inputValido.addEventListener('change', () => {
            condicionante.Resultado.Retorno = !!inputValido.value;
            if (inputValido.value) {
                condicionante.Resultado.Mensagem = '';
                inputMensagem.style.display = 'none';
            } else {
                inputMensagem.style.display = '';
            }
        });
        container.append(inputValido);

        const inputMensagem = document.createElement('textarea');
        inputMensagem.classList.add('govbr-forms-configurador-item-campo');
        inputMensagem.title = 'Mensagem da Validação';
        inputMensagem.value = condicionante.Resultado.Mensagem || '';
        inputMensagem.style.display = condicionante.Resultado.Retorno ? 'none' : '';
        inputMensagem.addEventListener('change', () => {
            condicionante.Resultado.Mensagem = inputMensagem.value;
        });
        container.append(inputMensagem);
    }

    // ************************
    // **** CONDICIONANTES ****
    // ************************

    /**
     * Retorna o valor padrão para as condicionantes de um item.
     * @template {GOVBRFormsUCValidacaoResultado|GOVBRFormsUCEventoRetorno} T
     * @returns {GOVBRFormsUCCondicionante<T>[]}
     */
    montaCondicionantesPadrao() {
        return [
            {
                Condicional: this.montaCondicionalAgregadaPadrao(),
                Resultado: JSON.parse(JSON.stringify(this.resultadoPadrao)),
            },
            {
                Condicional: null,
                Resultado: JSON.parse(JSON.stringify(this.resultadoPadrao)),
            },
        ];
    }

    /**
     * Monta o valor padrão para uma condicional agregada.
     * @param {(GOVBRFormsUCCondicionanteCondicional|GOVBRFormsUCCondicionanteCondicionalAgregada)[]} condicionais
     * @returns {GOVBRFormsUCCondicionanteCondicionalAgregada}
     */
    montaCondicionalAgregadaPadrao(condicionais = null) {
        return {
            Agregada: true,
            Condicionais: condicionais || [
                this.montaCondicionalSimplesPadrao(),
            ],
            Operador: 'e',
        };
    }

    /**
     * Monta o valor padrão para uma condicional simples
     * @returns {GOVBRFormsUCCondicionanteCondicional}
     */
    montaCondicionalSimplesPadrao() {
        return {
            Agregada: false,
            ValoresCondicao: [
                { Tipo: null, Id: null, Valor: null },
                { Tipo: null, Id: null, Valor: null },
                { Tipo: null, Id: null, Valor: null },
            ],
            Operador: null,
        };
    }

    /**
     * Monta os itens de condicionantes para o evento/validação.
     * @template {GOVBRFormsUCValidacao|GOVBRFormsUCEvento} T
     * @param {HTMLElement} alvo
     * @param {T[]} itens
     * @param {string[]} contexto
     * @param {() => T} fnNew
     * @param {(el: HTMLElement, val: GOVBRFormsUCCondicionante<GOVBRFormsUCValidacaoResultado|GOVBRFormsUCEventoRetorno>) => HTMLElement} fnMontaRetorno
     */
    montaItensCondicionantes(alvo, itens, contexto, fnNew, fnMontaRetorno) {
        const containerItens = document.createElement('div');
        containerItens.classList.add('govbr-forms-configurador-itens');
        alvo.append(containerItens);

        this.containerItens = containerItens;
        this.itens = itens;
        this.contexto = contexto || [];
        this.fnMontaRetorno = fnMontaRetorno;
        this.recriaArvoreItens();

        this.containerItens.addEventListener('pointermove', (event) => {
            let tg = /** @type {HTMLElement} */ (event.target);
            while (tg && !tg.classList.contains('govbr-forms-configurador-item-condicional-agregador')) {
                tg = tg.parentElement;
            }
            if (this.itemFoco) {
                this.itemFoco.classList.remove('govbr-forms-configurador-item-condicional-agregador-foco');
            }
            this.itemFoco = tg;
            if (this.itemFoco) {
                this.itemFoco.classList.add('govbr-forms-configurador-item-condicional-agregador-foco');
            }
        });

        const btnAdicionarNovo = document.createElement('button');
        btnAdicionarNovo.classList.add('govbr-forms-configurador-botao');
        btnAdicionarNovo.classList.add('govbr-forms-configurador-botao-novo');
        btnAdicionarNovo.title = 'Adicionar ' + this.descricaoNovo + ' ' + this.descricaoItem;
        btnAdicionarNovo.innerText = 'Adicionar ' + this.descricaoNovo + ' ' + this.descricaoItem;
        btnAdicionarNovo.addEventListener('click', () => {
            itens.push(fnNew());
            this.recriaArvoreItens();
        });
        alvo.append(btnAdicionarNovo);
    }

    /**
     * Recria a árvore de ítens após uma alteração nas condicionantes.
     */
    recriaArvoreItens() {
        this.containerItens.innerHTML = '';
        this.itens.forEach((item, idx) => {
            const containerItem = document.createElement('div');
            containerItem.classList.add('govbr-forms-configurador-item');
            const prefixoItem = document.createElement('div');
            prefixoItem.classList.add('govbr-forms-configurador-item-prefixo');
            prefixoItem.innerText = this.prefixoRetorno;
            containerItem.append(prefixoItem);
            const containerCondicionante = document.createElement('div');
            containerCondicionante.classList.add('govbr-forms-configurador-item-container');
            containerItem.append(containerCondicionante);

            item.Condicionantes.forEach((condicionante, idx) => {
                this.montaCondicionante(idx > 0, containerCondicionante, condicionante, this.fnMontaRetorno);
                if (idx > 0 && condicionante.Condicional !== null) {
                    containerCondicionante.append(
                        this.montaBotaoRemoverCondicionante(() => {
                            item.Condicionantes.splice(idx, 1);
                            this.recriaArvoreItens();
                        })
                    );
                }
                if (condicionante.Condicional !== null) {
                    containerCondicionante.append(
                        this.montaBotaoAdicionarCondicionante(() => {
                            /**
                             * @type {GOVBRFormsUCCondicionante<GOVBRFormsUCValidacaoResultado>}
                             */
                            const novaCondicionante = {
                                Condicional: this.montaCondicionalAgregadaPadrao(),
                                Resultado: /** @type {GOVBRFormsUCValidacaoResultado} */ (this.resultadoPadrao),
                            };
                            item.Condicionantes.splice(idx + 1, 0, novaCondicionante);
                            this.recriaArvoreItens();
                        })
                    );
                    const quebra = document.createElement('div');
                    quebra.style.width = '100%';
                    containerCondicionante.append(quebra);
                }
            });

            const btnRemover = document.createElement('button');
            btnRemover.classList.add('govbr-forms-configurador-botao');
            btnRemover.classList.add('govbr-forms-configurador-botao-remover-item');
            btnRemover.type = 'button';
            btnRemover.title = 'Remover ' + this.descricaoItem;
            const icone = document.createElement('i');
            icone.classList.add('fa-solid');
            icone.classList.add('fa-trash-can');
            btnRemover.append(icone);
            btnRemover.addEventListener('click', () => {
                this.itens.splice(idx, 1);
                this.recriaArvoreItens();
            });
            containerItem.append(btnRemover);
            this.containerItens.append(containerItem);
        });
    }

    /**
     * Monta o botão para remover a condicionante.
     * @param {() => void} fnRemove
     */
    montaBotaoRemoverCondicionante(fnRemove) {
        const btnRemover = document.createElement('button');
        btnRemover.classList.add('govbr-forms-configurador-botao');
        btnRemover.classList.add('govbr-forms-configurador-botao-remover-condicionante');
        btnRemover.type = 'button';
        btnRemover.title = 'Remover Condição';
        const icone = document.createElement('i');
        icone.classList.add('fa-solid');
        icone.classList.add('fa-trash-can');
        btnRemover.append(icone);
        btnRemover.addEventListener('click', fnRemove);
        return btnRemover;
    }

    /**
     * Monta o botão para adicionar uma condicionante.
     * @param {() => void} fnAdd
     */
    montaBotaoAdicionarCondicionante(fnAdd) {
        const btnAdicionar = document.createElement('button');
        btnAdicionar.classList.add('govbr-forms-configurador-botao');
        btnAdicionar.classList.add('govbr-forms-configurador-botao-adicionar-condicionante');
        btnAdicionar.type = 'button';
        btnAdicionar.title = 'Adicionar Condição';
        const icone = document.createElement('i');
        icone.classList.add('fa-solid');
        icone.classList.add('fa-plus');
        btnAdicionar.append(icone);
        btnAdicionar.addEventListener('click', fnAdd);
        return btnAdicionar;
    }

    /**
     * Monta um item de condicionante.
     * @param {boolean} isSenao
     * @param {HTMLElement} container
     * @param {GOVBRFormsUCCondicionante<GOVBRFormsUCValidacaoResultado> | GOVBRFormsUCCondicionante<GOVBRFormsUCEventoRetorno>} condicionante
     * @param {(el: HTMLElement, val: GOVBRFormsUCCondicionante<GOVBRFormsUCValidacaoResultado|GOVBRFormsUCEventoRetorno>) => HTMLElement} fnMontaRetorno
     */
    montaCondicionante(isSenao, container, condicionante, fnMontaRetorno) {
        const descricao = document.createElement('span');
        if (isSenao) {
            descricao.innerText = 'Senão';
            if (condicionante.Condicional !== null) {
                descricao.innerText = 'Senão, Se';
            }
        } else {
            descricao.innerText = 'Se';
        }
        descricao.classList.add('govbr-forms-configurador-item-condicionante-prefixo');
        container.append(descricao);
        if (condicionante.Condicional !== null && condicionante.Condicional.Agregada) {
            this.montaValidacaoCondicionanteAgregada(container, condicionante.Condicional);
        }

        const quebra = document.createElement('div');
        quebra.style.width = '100%';
        container.append(quebra);

        const containerRetorno = document.createElement('div');
        containerRetorno.classList.add('govbr-forms-configurador-item');
        const prefixoRetorno = document.createElement('div');
        prefixoRetorno.classList.add('govbr-forms-configurador-item-prefixo');
        prefixoRetorno.innerText = this.prefixoRetorno;
        containerRetorno.append(prefixoRetorno);
        const containerRetornoItem = document.createElement('div');
        containerRetornoItem.classList.add('govbr-forms-configurador-item-container');
        containerRetorno.append(containerRetornoItem);
        fnMontaRetorno(containerRetornoItem, condicionante);
        container.append(containerRetorno);
    }

    /**
     * Monta as validações para uma condicional agregada de uma condicionante.
     * @param {HTMLElement} container
     * @param {GOVBRFormsUCCondicionanteCondicionalAgregada} condicional
     * @param {GOVBRFormsUCCondicionanteCondicionalAgregada} pai
     * @param {number} idxPai
     */
    montaValidacaoCondicionanteAgregada(container, condicional, pai = null, idxPai = null) {
        const separadorAgregacao = document.createElement('div');
        separadorAgregacao.classList.add('govbr-forms-configurador-item-condicional-agregador');
        condicional.Condicionais.forEach((subCondicional, idx) => {
            if (idx > 0) {
                const operador = condicional.Operador;
                const containerOperador = document.createElement('div');
                containerOperador.classList.add('govbr-forms-configurador-item-condicional-operador');
                const inputOperador = document.createElement('select');
                inputOperador.classList.add('govbr-forms-configurador-item-campo');
                inputOperador.title = 'Campo alvo';
                inputOperador.required = true;
                inputOperador.append(this.criaOpcaoSelectLista('e', 'E'));
                inputOperador.append(this.criaOpcaoSelectLista('ou', 'OU'));
                inputOperador.value = operador || 'e';
                inputOperador.addEventListener('change', () => {
                    condicional.Operador = /** @type {GOVBRFormsUCCondicionanteOperadorAgregacao} */ (inputOperador.value);
                });
                containerOperador.append(inputOperador);
                separadorAgregacao.append(containerOperador);
            }
            const containerCondicional = document.createElement('div');
            containerCondicional.classList.add('govbr-forms-configurador-item-condicional-item');
            if (subCondicional.Agregada) {
                this.montaValidacaoCondicionanteAgregada(containerCondicional, /** @type { GOVBRFormsUCCondicionanteCondicionalAgregada } */ (subCondicional), condicional, idx);
            } else {
                this.montaValidacaoCondicionanteSimples(containerCondicional, /** @type { GOVBRFormsUCCondicionanteCondicional } */ (subCondicional));
            }
            separadorAgregacao.append(containerCondicional);
            separadorAgregacao.append(
                this.montaBotaoAdicionarCondicional(() => {
                    const novaCondicional = this.montaCondicionalSimplesPadrao();
                    if (condicional.Condicionais.length > 1) {
                        const condicionalPai = this.montaCondicionalAgregadaPadrao([subCondicional, novaCondicional]);
                        condicional.Condicionais[idx] = condicionalPai;
                    } else {
                        condicional.Condicionais.push(novaCondicional);
                    }
                    this.recriaArvoreItens();
                })
            );
            if (condicional.Condicionais.length > 1 || pai) {
                separadorAgregacao.append(
                    this.montaBotaoRemoverCondicional(() => {
                        condicional.Condicionais.splice(idx, 1);
                        if (pai) {
                            pai.Condicionais.splice(idxPai, 1, condicional.Condicionais[0]);
                        }
                        this.recriaArvoreItens();
                    })
                );
            }
        });
        container.append(separadorAgregacao);
    }

    /**
     * Monta o botão para adicionar uma nova condicional
     * @param {() => void} fnAdd
     */
    montaBotaoAdicionarCondicional(fnAdd) {
        const btnAdicionar = document.createElement('button');
        btnAdicionar.classList.add('govbr-forms-configurador-botao');
        btnAdicionar.classList.add('govbr-forms-configurador-botao-adicionar-condicional');
        btnAdicionar.type = 'button';
        btnAdicionar.title = 'Adicionar Condicional';
        const icone = document.createElement('i');
        icone.classList.add('fa-solid');
        icone.classList.add('fa-plus');
        btnAdicionar.append(icone);
        btnAdicionar.addEventListener('click', fnAdd);
        return btnAdicionar;
    }

    /**
     * Monta o botão para remover uma nova condicional
     * @param {() => void} fnRemove
     */
    montaBotaoRemoverCondicional(fnRemove) {
        const btnAdicionar = document.createElement('button');
        btnAdicionar.classList.add('govbr-forms-configurador-botao');
        btnAdicionar.classList.add('govbr-forms-configurador-botao-remover-condicional');
        btnAdicionar.type = 'button';
        btnAdicionar.title = 'Remover Condicional';
        const icone = document.createElement('i');
        icone.classList.add('fa-solid');
        icone.classList.add('fa-trash-can');
        btnAdicionar.append(icone);
        btnAdicionar.addEventListener('click', fnRemove);
        return btnAdicionar;
    }

    /**
     * Monta as validações para uma condicional simples de uma condicionante.
     * @param {HTMLElement} container
     * @param {GOVBRFormsUCCondicionanteCondicional} condicional
     */
    montaValidacaoCondicionanteSimples(container, condicional) {
        const fnChangeInputCampo = () => {
            inputOperador.innerHTML = '';
            inputOperador.append(this.criaOpcaoSelectLista('', 'Selecione...'));
            if (inputCampo.value) {
                inputOperador.disabled = false;
                const campo = campos[inputCampo.value];
                this.montaOpcoesInputOperadorTipoCampo(inputOperador, campo.dataFormato);
            } else {
                inputOperador.value = '';
                inputOperador.disabled = true;
            }
            fnChangeInputOperador();
        };

        const fnChangeInputOperador = () => {
            this.trataOpcoesOperadorTipoCampo(/** @type {GOVBRFormsUCCondicionanteCondicionalOperadores} */ (inputOperador.value), campos, container, [
                inputsValores1,
                separadorE,
                inputsValores2,
            ]);
            if (!inputOperador.value) {
                inputTipoResultado.value = 'valor';
                inputTipoResultado.disabled = true;
                inputValorResultado.value = '';
                inputValorResultado.disabled = true;
                inputCampoResultado.value = '';
                inputCampoResultado.disabled = true;
                inputTipoResultado2.value = 'valor';
                inputTipoResultado2.disabled = true;
                inputValorResultado2.value = '';
                inputValorResultado2.disabled = true;
                inputCampoResultado2.value = '';
                inputCampoResultado2.disabled = true;
            }
        };

        const campos = /** @type {Record<string, GOVBRFormsUCComponenteInput>} */ (this.getCamposDisponiveis(true, false));

        const inputCampo = document.createElement('select');
        inputCampo.classList.add('govbr-forms-configurador-item-campo');
        inputCampo.title = 'Campo alvo';
        inputCampo.required = this.condicionalObrigatoria;
        if (this.identificadorAlvo) {
            inputCampo.value = this.identificadorAlvo;
            if (!condicional.ValoresCondicao[0]) {
                condicional.ValoresCondicao.push({
                    Tipo: 'componente',
                    Id: '',
                });
            }
            condicional.ValoresCondicao[0].Id = this.identificadorAlvo;
        }
        inputCampo.append(this.criaOpcaoSelectLista('', this.condicionalObrigatoria ? 'Selecione...' : 'Verdadeiro'));
        Object.values(campos).forEach((componente) => {
            inputCampo.append(this.criaOpcaoSelectLista(componente.identificador, componente.dataIdentificador + ' (' + componente.titulo + ')'));
        });
        inputCampo.addEventListener('change', () => {
            fnChangeInputCampo();
            if (!condicional.ValoresCondicao[0]) {
                condicional.ValoresCondicao.push({
                    Tipo: 'componente',
                    Id: '',
                });
            }
            condicional.ValoresCondicao[0].Id = inputCampo.value;
        });
        container.append(inputCampo);

        const inputOperador = document.createElement('select');
        inputOperador.classList.add('govbr-forms-configurador-item-campo');
        inputOperador.title = 'Operador';
        inputOperador.disabled = true;
        inputOperador.required = true;
        inputOperador.addEventListener('change', () => {
            fnChangeInputOperador();
            condicional.Operador = /** @type {GOVBRFormsUCCondicionanteCondicionalOperadores} */ (inputOperador.value);
        });
        container.append(inputOperador);

        const inputsValores1 = this.montaInputsTiposResultados(container, condicional, 1);
        const [inputTipoResultado, inputValorResultado, inputCampoResultado, fnChangeInputTipoResultado] = inputsValores1;
        const separadorE = document.createElement('span');
        separadorE.innerText = ' e ';
        separadorE.style.display = 'none';
        container.append(separadorE);
        const inputsValores2 = this.montaInputsTiposResultados(container, condicional, 2);
        const [inputTipoResultado2, inputValorResultado2, inputCampoResultado2, fnChangeInputTipoResultado2] = inputsValores2;

        if (condicional.ValoresCondicao[0]) {
            inputCampo.value = condicional.ValoresCondicao[0].Id || '';
        }
        fnChangeInputCampo();
        if (condicional.Operador) {
            inputOperador.value = condicional.Operador;
        }
        fnChangeInputOperador();
        if (condicional.ValoresCondicao[1]) {
            inputTipoResultado.value = condicional.ValoresCondicao[1].Tipo || 'valor';
        }
        if (inputOperador.value) {
            fnChangeInputTipoResultado();
        }
        if (condicional.ValoresCondicao[1]) {
            inputValorResultado.value = condicional.ValoresCondicao[1].Valor;
            inputCampoResultado.value = condicional.ValoresCondicao[1].Valor;
        }
        if (condicional.ValoresCondicao[2]) {
            inputTipoResultado2.value = condicional.ValoresCondicao[2].Tipo;
        }
        if (inputOperador.value) {
            fnChangeInputTipoResultado2();
        }
        if (condicional.ValoresCondicao[2]) {
            inputValorResultado2.value = condicional.ValoresCondicao[2].Valor;
            inputCampoResultado2.value = condicional.ValoresCondicao[2].Valor;
        }
    }

    /**
     * Monta as opções pro operador com base no tipo do campo.
     * @param {HTMLSelectElement} inputOperador
     * @param {import('./GOVBRFormsUCComponente.mjs').GOVBRFormsUCComponenteInputFormatos} formato
     */
    montaOpcoesInputOperadorTipoCampo(inputOperador, formato) {
        const opcoes = [
            ['igual', 'For Igual a'],
            ['diferente', 'For Diferente de'],
        ];
        switch (formato) {
            case 'texto':
            case 'textarea':
            case 'editor':
            case 'telefone':
            case 'email':
            case 'cpf-cnpj':
                opcoes.push(
                    ['contem', 'Contém'],
                    ['nao-contem', 'Não contém'],
                    ['inicia-com', 'Inicia com'],
                    ['termina-com', 'Termina com'],
                    ['expressao-regular', 'Equivaler a expressão regular']
                );
                break;
            case 'numero':
            case 'data-hora':
                opcoes.push(
                    ['maior-que', 'For maior que'],
                    ['menor-que', 'For menor que'],
                    ['maior-igual', 'For maior ou igual a'],
                    ['menor-igual', 'For menor ou igual a'],
                    ['entre', 'Estiver entre']
                );
                break;
            case 'lista':
                opcoes.push(['contem', 'Contém'], ['nao-contem', 'Não Contém']);
                break;
            case 'booleano':
            default:
                break;
        }
        opcoes.push(['nulo', 'For vazio'], ['nao-nulo', 'Não for vazio']);
        opcoes.forEach(([valor, nome]) => inputOperador.append(this.criaOpcaoSelectLista(valor, nome)));
    }

    /**
     * Monta os inputs de tipos de resultados.
     * @param {HTMLElement} container
     * @param {GOVBRFormsUCCondicionanteCondicional} condicional
     * @param {number} idx
     * @returns {[HTMLSelectElement, HTMLInputElement, HTMLSelectElement, () => void]}
     */
    montaInputsTiposResultados(container, condicional, idx) {
        const fnChangeInputTipoResultado = () => {
            if (inputTipoResultado.getAttribute('data-force-value')) {
                inputTipoResultado.value = inputTipoResultado.getAttribute('data-force-value');
                inputTipoResultado.disabled = true;
                inputTipoResultado.style.display = 'none';
            } else if (inputTipoResultado.style.display === 'none') {
                inputValorResultado.disabled = true;
                inputValorResultado.style.display = 'none';
                inputCampoResultado.disabled = true;
                inputCampoResultado.style.display = 'none';
                return;
            }
            if (inputTipoResultado.value === 'componente') {
                inputCampoResultado.disabled = false;
                inputCampoResultado.style.display = '';
                inputValorResultado.disabled = true;
                inputValorResultado.style.display = 'none';
            } else {
                inputValorResultado.disabled = false;
                inputValorResultado.style.display = '';
                inputCampoResultado.disabled = true;
                inputCampoResultado.style.display = 'none';
            }
        };

        const inputTipoResultado = document.createElement('select');
        inputTipoResultado.classList.add('govbr-forms-configurador-item-campo');
        inputTipoResultado.title = 'Tipo Resultado';
        inputTipoResultado.disabled = true;
        inputTipoResultado.required = true;
        inputTipoResultado.append(this.criaOpcaoSelectLista('valor', 'o Valor'));
        inputTipoResultado.append(this.criaOpcaoSelectLista('componente', 'o Valor do Campo'));
        inputTipoResultado.addEventListener('change', () => {
            fnChangeInputTipoResultado();
            if (!inputTipoResultado.value) {
                return;
            }
            if (!condicional.ValoresCondicao[idx]) {
                condicional.ValoresCondicao.push({
                    Tipo: /** @type {"componente" | "valor"} */ (inputTipoResultado.value),
                    Id: null,
                    Valor: null,
                });
            }
            condicional.ValoresCondicao[idx].Tipo = /** @type {"componente" | "valor"} */ (inputTipoResultado.value);
        });
        container.append(inputTipoResultado);

        const inputValorResultado = document.createElement('input');
        inputValorResultado.type = 'text';
        inputValorResultado.classList.add('govbr-forms-configurador-item-campo');
        inputValorResultado.title = 'Resultado';
        inputValorResultado.disabled = true;
        inputValorResultado.required = true;
        inputValorResultado.addEventListener('change', () => {
            if (!condicional.ValoresCondicao[idx]) {
                condicional.ValoresCondicao.push({
                    Tipo: null,
                    Id: null,
                    Valor: null,
                });
            }
            condicional.ValoresCondicao[idx].Tipo = 'valor';
            condicional.ValoresCondicao[idx].Valor = inputValorResultado.value;
        });
        container.append(inputValorResultado);

        const inputCampoResultado = document.createElement('select');
        inputCampoResultado.classList.add('govbr-forms-configurador-item-campo');
        inputCampoResultado.title = 'Campo de Resultado';
        inputCampoResultado.required = true;
        inputCampoResultado.disabled = true;
        inputCampoResultado.style.display = 'none';
        inputCampoResultado.append(this.criaOpcaoSelectLista('', 'Selecione...'));
        inputCampoResultado.addEventListener('change', () => {
            if (!condicional.ValoresCondicao[idx]) {
                condicional.ValoresCondicao.push({
                    Tipo: null,
                    Id: null,
                    Valor: null,
                });
            }
            condicional.ValoresCondicao[idx].Tipo = 'componente';
            condicional.ValoresCondicao[idx].Valor = inputCampoResultado.value;
        });
        container.append(inputCampoResultado);

        return [inputTipoResultado, inputValorResultado, inputCampoResultado, fnChangeInputTipoResultado];
    }

    /**
     * Trata os campos a serem exibidos com base na opção do operador selecionado.
     * @param {GOVBRFormsUCCondicionanteCondicionalOperadores} operador
     * @param {Record<string, GOVBRFormsUCComponenteInput>} campos
     * @param {HTMLElement} container
     * @param {[[HTMLSelectElement, HTMLInputElement, HTMLSelectElement, () => void], HTMLSpanElement, [HTMLSelectElement, HTMLInputElement, HTMLSelectElement, () => void]]} inputs
     */
    trataOpcoesOperadorTipoCampo(operador, campos, container, inputs) {
        const [
            [inputTipoResultado, inputValorResultado, inputCampoResultado, fnChangeInputTipoResultado],
            separadorE,
            [inputTipoResultado2, inputValorResultado2, inputCampoResultado2, fnChangeInputTipoResultado2],
        ] = inputs;
        inputTipoResultado.style.display = '';
        inputTipoResultado.disabled = false;
        inputTipoResultado.setAttribute('data-force-value', '');
        inputCampoResultado.innerHTML = '';
        inputCampoResultado.append(this.criaOpcaoSelectLista('', 'Selecione...'));
        separadorE.style.display = 'none';
        inputTipoResultado2.style.display = 'none';
        inputTipoResultado2.disabled = true;
        inputCampoResultado2.innerHTML = '';
        inputCampoResultado2.append(this.criaOpcaoSelectLista('', 'Selecione...'));
        container.classList.remove('govbr-forms-configurador-item-condicional-item-entre');

        switch (operador) {
            case 'nulo':
            case 'nao-nulo':
                inputTipoResultado.style.display = 'none';
                inputValorResultado.style.display = 'none';
                inputCampoResultado.style.display = 'none';
                break;
            case 'expressao-regular':
                inputCampoResultado.style.display = 'none';
                inputTipoResultado.setAttribute('data-force-value', 'valor');
                break;
            case 'entre':
                separadorE.style.display = '';
                inputTipoResultado2.style.display = '';
                inputTipoResultado2.disabled = false;
                inputValorResultado2.style.display = '';
                inputCampoResultado2.style.display = '';
                Object.values(campos).forEach((campo) => {
                    inputCampoResultado2.append(this.criaOpcaoSelectLista(campo.identificador, campo.dataIdentificador + ' (' + campo.titulo + ')'));
                });
                container.classList.add('govbr-forms-configurador-item-condicional-item-entre');
            /* FALLTHROUGH */
            case 'igual':
            case 'diferente':
            case 'maior-que':
            case 'menor-que':
            case 'maior-igual':
            case 'menor-igual':
            case 'contem':
            case 'nao-contem':
            case 'inicia-com':
            case 'termina-com':
                Object.values(campos).forEach((campo) => {
                    inputCampoResultado.append(this.criaOpcaoSelectLista(campo.identificador, campo.dataIdentificador + ' (' + campo.titulo + ')'));
                });
                break;
            default:
                break;
        }
        fnChangeInputTipoResultado();
        fnChangeInputTipoResultado2();
    }

    /**
     * @param {string} valor
     * @param {string} nome
     */
    criaOpcaoSelectLista(valor, nome) {
        const opt = document.createElement('option');
        opt.value = valor;
        opt.innerText = nome;
        return opt;
    }

    /**
     * Retorna os campos disponíveis.
     * @param {boolean} apenasInputs
     * @param {boolean} contextoExato
     * @returns {Record<string, GOVBRFormsUCComponente>}
     */
    getCamposDisponiveis(apenasInputs, contextoExato) {
        /**
         * @param {Record<string, GOVBRFormsUCComponenteInput>} accum
         * @param {GOVBRFormsUCComponente|GOVBRFormsUCComponenteContainer} el
         */
        const fnReduceCampos = (accum, el) => {
            if (!apenasInputs || el.tipo === 'input') {
                const contextoMultilinha = el.getContextoContainersMultilinha();
                // Se configurado o contextoExato, apenas interagem com campos no mesmo contexto, senão interage com o mesmo ou menores.
                // Basicamente se for pra validar uma condição, (contextoExato = false), pode utilizar campos nos elementos pai do multilinha (contexto menor), por exemplo um campo na raiz de formulário.
                // Mas se for tentar modificar algo em um campo, (contextoExato = true), so pode mecher em campos dentro do multilinha, ou você teria, por ex, dois campos dentro do multilinha "brigando"
                // para definir algo em um campo só fora.
                // Não pode mecher ou interagir em campos em profundidades maiores (caso tenha um multilinha dentro do multilinha onde o evento ocorre) senão irá tentar mudar um campo qeu não existe.
                const tamanhoContextoValido = contextoExato ? this.contexto.length === contextoMultilinha.length : this.contexto.length >= contextoMultilinha.length;
                // Valida além do tamanho acima, de que os campos trazidos todos pertencem ao exato mesmo contexto para evitar um campo em um multilinha mecher em um campo em um outro multilinha nada a ver.
                if (tamanhoContextoValido && contextoMultilinha.every((e, idx) => e === this.contexto[idx])) {
                    accum[el.identificador] = /** @type {GOVBRFormsUCComponenteInput} */ (el);
                }
            }
            if (el.isContainer) {
                /** @type {GOVBRFormsUCComponenteContainer} */ (el).filhos.reduce(fnReduceCampos, accum);
            }
            return accum;
        };
        return this.form.componentes.reduce(fnReduceCampos, {});
    }
}
