"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RegraConvencaoNomenclatura = void 0;
const declaracoes_1 = require("../../declaracoes");
/**
 * Regra que enforça convenções de nomenclatura.
 *
 * Exemplos:
 * - Variáveis em caixaCamelo: `var meuNome` (não `var MeuNome` ou `var meu_nome`)
 * - Constantes em CAIXA_ALTA: `constante PI_VALOR` (não `constante piValor`)
 * - Funções em caixaCamelo: `função calcularTotal()` (não `função CalcularTotal()`)
 */
class RegraConvencaoNomenclatura {
    constructor(opcoes = {}) {
        this.nome = 'convencao-nomenclatura';
        this.descricao = 'Enforça convenções de nomenclatura para variáveis, constantes e funções';
        this.opcoes = {
            variavel: opcoes.variavel || 'caixaCamelo',
            constante: opcoes.constante || 'CAIXA_ALTA',
            funcao: opcoes.funcao || 'caixaCamelo',
        };
    }
    aplicarEmDeclaracao(declaracao) {
        // Valida/transforma nomes de variáveis
        if (declaracao instanceof declaracoes_1.Var) {
            return this.aplicarConvencaoVar(declaracao);
        }
        // Valida/transforma nomes de constantes
        if (declaracao instanceof declaracoes_1.Const) {
            return this.aplicarConvencaoConst(declaracao);
        }
        // Valida/transforma nomes de funções
        if (declaracao instanceof declaracoes_1.FuncaoDeclaracao) {
            return this.aplicarConvencaoFuncao(declaracao);
        }
        return declaracao;
    }
    /**
     * Aplica convenção em declaração Var.
     */
    aplicarConvencaoVar(declaracao) {
        if (!this.opcoes.variavel)
            return declaracao;
        const nomeAtual = declaracao.simbolo.lexema;
        const nomeConvertido = this.converterNome(nomeAtual, this.opcoes.variavel);
        if (nomeAtual !== nomeConvertido) {
            declaracao.simbolo.lexema = nomeConvertido;
        }
        return declaracao;
    }
    /**
     * Aplica convenção em declaração Const.
     */
    aplicarConvencaoConst(declaracao) {
        if (!this.opcoes.constante)
            return declaracao;
        const nomeAtual = declaracao.simbolo.lexema;
        const nomeConvertido = this.converterNome(nomeAtual, this.opcoes.constante);
        if (nomeAtual !== nomeConvertido) {
            declaracao.simbolo.lexema = nomeConvertido;
        }
        return declaracao;
    }
    /**
     * Aplica convenção em declaração de Função.
     */
    aplicarConvencaoFuncao(declaracao) {
        if (!this.opcoes.funcao)
            return declaracao;
        const nomeAtual = declaracao.simbolo.lexema;
        const nomeConvertido = this.converterNome(nomeAtual, this.opcoes.funcao);
        if (nomeAtual !== nomeConvertido) {
            declaracao.simbolo.lexema = nomeConvertido;
        }
        return declaracao;
    }
    /**
     * Converte um nome para a convenção especificada.
     */
    converterNome(nome, convencao) {
        switch (convencao) {
            case 'caixaCamelo':
                return this.paraCamelCase(nome);
            case 'caixa_cobra':
                return this.paraSnakeCase(nome);
            case 'CaixaPascal':
                return this.paraPascalCase(nome);
            case 'CAIXA_ALTA':
                return this.paraUpperCase(nome);
            default:
                return nome;
        }
    }
    /**
     * Converte nome para camelCase.
     */
    paraCamelCase(nome) {
        // Se tem underscores, divide por eles
        if (nome.includes('_')) {
            const palavras = nome.split(/[_\s]+/);
            return (palavras[0].toLowerCase() +
                palavras
                    .slice(1)
                    .map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())
                    .join(''));
        }
        // Se está em PascalCase, converte para camelCase
        if (nome.charAt(0) === nome.charAt(0).toUpperCase()) {
            return nome.charAt(0).toLowerCase() + nome.slice(1);
        }
        // Já está em camelCase
        return nome;
    }
    /**
     * Converte nome para snake_case.
     */
    paraSnakeCase(nome) {
        return (nome
            // Adiciona underscore antes de letras maiúsculas
            .replace(/([A-Z])/g, '_$1')
            .toLowerCase()
            // Remove underscores duplicados
            .replace(/__+/g, '_')
            // Remove underscore inicial se houver
            .replace(/^_/, ''));
    }
    /**
     * Converte nome para PascalCase.
     */
    paraPascalCase(nome) {
        const palavras = nome.split(/[_\s]+/);
        return palavras.map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join('');
    }
    /**
     * Converte nome para UPPER_CASE.
     */
    paraUpperCase(nome) {
        return this.paraSnakeCase(nome).toUpperCase();
    }
    /**
     * Valida se um nome está na convenção especificada.
     */
    validarNome(nome, convencao) {
        return nome === this.converterNome(nome, convencao);
    }
}
exports.RegraConvencaoNomenclatura = RegraConvencaoNomenclatura;
//# sourceMappingURL=convencao-nomenclatura.js.map