"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EstilizadorDelegua = void 0;
/**
 * Estilizador de código para Delégua.
 * Aplica transformações no AST para enforcar convenções e melhorar qualidade do código.
 */
class EstilizadorDelegua {
    constructor(regras = []) {
        this.regras = regras;
        this.violacoes = [];
        this.modoValidacao = false;
    }
    adicionarRegra(regra) {
        this.regras.push(regra);
    }
    removerRegra(nomeRegra) {
        this.regras = this.regras.filter((r) => r.nome !== nomeRegra);
    }
    /**
     * Aplica as regras de estilização recursivamente em uma declaração.
     * @param declaracao A declaração a ser estilizada.
     * @returns A declaração estilizada.
     */
    estilizarDeclaracao(declaracao) {
        let declaracaoAtual = declaracao;
        // Aplica regras de declaração
        for (const regra of this.regras) {
            if (regra.aplicarEmDeclaracao) {
                if (this.modoValidacao) {
                    // Em modo validação, clona a declaração antes de aplicar
                    const declaracaoClonada = this.clonarDeclaracao(declaracaoAtual);
                    const declaracaoModificada = regra.aplicarEmDeclaracao(declaracaoClonada);
                    // Verifica se houve mudança
                    if (this.declaracaoFoiModificada(declaracaoAtual, declaracaoModificada)) {
                        this.violacoes.push({
                            regra: regra.nome,
                            mensagem: `${regra.descricao}`,
                            linha: declaracao.linha,
                            hashArquivo: declaracao.hashArquivo,
                            severidade: 'aviso',
                        });
                    }
                }
                else {
                    // Em modo normal, aplica a transformação
                    declaracaoAtual = regra.aplicarEmDeclaracao(declaracaoAtual);
                }
            }
        }
        // Recursivamente estiliza construtos dentro da declaração
        if (!this.modoValidacao) {
            this.estilizarCamposDeclaracao(declaracaoAtual);
        }
        return declaracaoAtual;
    }
    /**
     * Verifica se uma declaração foi modificada comparando propriedades relevantes.
     */
    declaracaoFoiModificada(original, modificada) {
        // Compara lexema do símbolo (para nomes)
        if (original.simbolo && modificada.simbolo) {
            if (original.simbolo.lexema !== modificada.simbolo.lexema) {
                return true;
            }
        }
        // Compara tipo
        if (original.tipo !== modificada.tipo) {
            return true;
        }
        // Compara tipoExplicito
        if (original.tipoExplicito !== modificada.tipoExplicito) {
            return true;
        }
        return false;
    }
    /**
     * Clona uma declaração de forma superficial.
     */
    clonarDeclaracao(declaracao) {
        // Cria um novo objeto com o mesmo protótipo
        const clone = Object.create(Object.getPrototypeOf(declaracao));
        // Copia todas as propriedades
        for (const chave in declaracao) {
            if (declaracao.hasOwnProperty(chave)) {
                // Para objetos aninhados, clona também
                if (typeof declaracao[chave] === 'object' && declaracao[chave] !== null) {
                    if (Array.isArray(declaracao[chave])) {
                        clone[chave] = [...declaracao[chave]];
                    }
                    else {
                        clone[chave] = Object.assign({}, declaracao[chave]);
                    }
                }
                else {
                    clone[chave] = declaracao[chave];
                }
            }
        }
        return clone;
    }
    /**
     * Estiliza construtos dentro de uma declaração.
     * @param declaracao A declaração cujos campos serão estilizados.
     */
    estilizarCamposDeclaracao(declaracao) {
        // Itera sobre as propriedades da declaração
        for (const chave in declaracao) {
            if (!declaracao.hasOwnProperty(chave))
                continue;
            const valor = declaracao[chave];
            // Se é um construto, estiliza
            if (valor && typeof valor === 'object' && 'aceitar' in valor) {
                if (this.ehConstruto(valor)) {
                    declaracao[chave] = this.estilizarConstruto(valor);
                }
            }
            // Se é um array, estiliza cada elemento
            if (Array.isArray(valor)) {
                for (let i = 0; i < valor.length; i++) {
                    if (this.ehDeclaracao(valor[i])) {
                        valor[i] = this.estilizarDeclaracao(valor[i]);
                    }
                    else if (this.ehConstruto(valor[i])) {
                        valor[i] = this.estilizarConstruto(valor[i]);
                    }
                }
            }
        }
    }
    /**
     * Aplica as regras de estilização em um construto.
     * @param construto O construto a ser estilizado.
     * @returns O construto estilizado.
     */
    estilizarConstruto(construto) {
        let construtoAtual = construto;
        // Aplica regras de construto
        for (const regra of this.regras) {
            if (regra.aplicarEmConstruto) {
                if (this.modoValidacao) {
                    // Em modo validação, não modifica, apenas verifica
                    const construtoOriginal = JSON.stringify(construtoAtual);
                    const construtoModificado = regra.aplicarEmConstruto(construtoAtual);
                    if (JSON.stringify(construtoModificado) !== construtoOriginal) {
                        this.violacoes.push({
                            regra: regra.nome,
                            mensagem: `${regra.descricao} não foi aplicada`,
                            linha: construto.linha || 0,
                            hashArquivo: -1,
                            severidade: 'aviso',
                        });
                    }
                }
                else {
                    construtoAtual = regra.aplicarEmConstruto(construtoAtual);
                }
            }
        }
        // Recursivamente estiliza campos do construto
        this.estilizarCamposConstruto(construtoAtual);
        return construtoAtual;
    }
    /**
     * Estiliza campos dentro de um construto.
     * @param construto O construto cujos campos serão estilizados.
     */
    estilizarCamposConstruto(construto) {
        for (const chave in construto) {
            if (!construto.hasOwnProperty(chave))
                continue;
            const valor = construto[chave];
            if (valor && typeof valor === 'object' && 'aceitar' in valor) {
                if (this.ehConstruto(valor)) {
                    construto[chave] = this.estilizarConstruto(valor);
                }
                else if (this.ehDeclaracao(valor)) {
                    construto[chave] = this.estilizarDeclaracao(valor);
                }
            }
            if (Array.isArray(valor)) {
                for (let i = 0; i < valor.length; i++) {
                    if (this.ehDeclaracao(valor[i])) {
                        valor[i] = this.estilizarDeclaracao(valor[i]);
                    }
                    else if (this.ehConstruto(valor[i])) {
                        valor[i] = this.estilizarConstruto(valor[i]);
                    }
                }
            }
        }
    }
    /**
     * Verifica se um objeto é uma Declaração.
     */
    ehDeclaracao(obj) {
        return obj && typeof obj === 'object' && 'paraTexto' in obj && 'linha' in obj && 'hashArquivo' in obj;
    }
    /**
     * Verifica se um objeto é um Construto.
     */
    ehConstruto(obj) {
        return obj && typeof obj === 'object' && 'aceitar' in obj && !('paraTexto' in obj);
    }
    estilizar(declaracoes) {
        this.modoValidacao = false;
        this.violacoes = [];
        const declaracoesEstilizadas = [];
        for (const declaracao of declaracoes) {
            declaracoesEstilizadas.push(this.estilizarDeclaracao(declaracao));
        }
        return declaracoesEstilizadas;
    }
    validar(declaracoes) {
        this.modoValidacao = true;
        this.violacoes = [];
        // Aplica estilização em modo validação (não modifica, apenas detecta violações)
        for (const declaracao of declaracoes) {
            this.estilizarDeclaracao(declaracao);
        }
        const violacoesEncontradas = [...this.violacoes];
        this.violacoes = [];
        this.modoValidacao = false;
        return violacoesEncontradas;
    }
}
exports.EstilizadorDelegua = EstilizadorDelegua;
//# sourceMappingURL=estilizador-delegua.js.map