import { config, LIMITES_PADRAO, traverse } from '../../core/config/index.js';
import { messages } from '../../core/messages/index.js';
import { agruparPor, detectarComentariosPendentes, detectarFrameworks, detectarLogsDebug, filtrarOcorrenciasSuprimidas, isWhitelistedConstant, splitLines } from '../../shared/helpers/index.js';
import { criarOcorrencia } from '../../types/index.js';
let frameworksDetectados = null;
const LIMITES = {
    LINHAS_FUNCAO: LIMITES_PADRAO.CODIGO.MAX_LINHAS_FUNCAO,
    PARAMETROS_FUNCAO: LIMITES_PADRAO.CODIGO.MAX_PARAMETROS_FUNCAO,
    MAX_PARAMETROS_CRITICO: LIMITES_PADRAO.CODIGO.MAX_PARAMETROS_CRITICO,
    CALLBACKS_ANINHADOS: LIMITES_PADRAO.CODIGO.MAX_NESTED_CALLBACKS,
    COMPLEXIDADE_COGNITIVA: LIMITES_PADRAO.CODIGO.MAX_COMPLEXIDADE_COGNITIVA,
    REGEX_COMPLEXA_LENGTH: LIMITES_PADRAO.CODIGO.MAX_REGEX_LENGTH,
    MAX_ANINHAMENTO_IF: LIMITES_PADRAO.CODIGO.MAX_ANINHAMENTO_IF,
    MAX_LINHAS_ARQUIVO: LIMITES_PADRAO.CODIGO.MAX_LINHAS_ARQUIVO
};
const visitorFragil = {
    CatchClause(path, state) {
        const visitorState = state;
        const fragilidades = visitorState.resultados.get('codigo-fragil') || [];
        const body = path.node.body.body;
        const linha = path.node.loc?.start.line || 0;
        if (body.length === 0) {
            fragilidades.push({
                tipo: 'catch-vazio',
                linha,
                coluna: path.node.loc?.start.column || 0,
                severidade: 'media',
                contexto: 'Bloco catch vazio'
            });
        }
        else if (body.length === 1 && isSingleConsoleLog(body[0])) {
            fragilidades.push({
                tipo: 'catch-apenas-log',
                linha,
                coluna: path.node.loc?.start.column || 0,
                severidade: 'baixa',
                contexto: 'Catch apenas com console.log'
            });
        }
        visitorState.resultados.set('codigo-fragil', fragilidades);
    },
    IfStatement(path, state) {
        const visitorState = state;
        const fragilidades = visitorState.resultados.get('codigo-fragil') || [];
        let depth = 0;
        let current = path;
        while (current) {
            if (current.isIfStatement())
                depth++;
            current = current.parentPath;
        }
        if (depth > LIMITES.MAX_ANINHAMENTO_IF) {
            fragilidades.push({
                tipo: 'if-muito-aninhado',
                linha: path.node.loc?.start.line || 0,
                coluna: path.node.loc?.start.column || 0,
                severidade: depth > LIMITES.MAX_ANINHAMENTO_IF + 1 ? 'alta' : 'media',
                contexto: `Condicionais aninhadas demais (nível ${depth}, máx: ${LIMITES.MAX_ANINHAMENTO_IF})`
            });
        }
        visitorState.resultados.set('codigo-fragil', fragilidades);
    },
    FunctionDeclaration(path, state) {
        const visitorState = state;
        const fragilidades = visitorState.resultados.get('codigo-fragil') || [];
        const maxLinhas = config.ANALISE_LIMITES?.CODIGO_FRAGIL?.MAX_LINHAS_FUNCAO ?? LIMITES.LINHAS_FUNCAO;
        const node = path.node;
        if (node.body?.type === 'BlockStatement') {
            const inicio = node.loc?.start.line || 0;
            const fim = node.loc?.end.line || 0;
            const numLinhas = fim - inicio;
            if (numLinhas > maxLinhas) {
                fragilidades.push({
                    tipo: 'funcao-longa',
                    linha: inicio,
                    coluna: node.loc?.start.column || 0,
                    severidade: numLinhas > maxLinhas * 2 ? 'alta' : 'media',
                    contexto: `Função com ${numLinhas} linhas (máx: ${maxLinhas})`
                });
            }
        }
        visitorState.resultados.set('codigo-fragil', fragilidades);
    },
    NumericLiteral(path, state) {
        const visitorState = state;
        const fragilidades = visitorState.resultados.get('codigo-fragil') || [];
        const value = path.node.value;
        if (isInVariableDeclarator(path) || isInArrayIndex(path))
            return;
        if (!frameworksDetectados) {
            frameworksDetectados = detectarFrameworks(process.cwd()).map(arquivo => arquivo.name);
        }
        if (isWhitelistedConstant(value, frameworksDetectados))
            return;
        fragilidades.push({
            tipo: 'magic-number',
            linha: path.node.loc?.start.line || 0,
            coluna: path.node.loc?.start.column || 0,
            severidade: 'baixa',
            contexto: `Número mágico '${value}' detectado`
        });
        visitorState.resultados.set('codigo-fragil', fragilidades);
    }
};
export const analistaCodigoFragil = {
    nome: 'codigo-fragil',
    categoria: 'qualidade',
    descricao: 'Detecta padrões de código que podem levar a problemas futuros',
    limites: {
        maxLinhasFuncao: config.ANALISE_LIMITES?.CODIGO_FRAGIL?.MAX_LINHAS_FUNCAO ?? LIMITES.LINHAS_FUNCAO,
        maxParametros: config.ANALISE_LIMITES?.CODIGO_FRAGIL?.MAX_PARAMETROS ?? LIMITES.PARAMETROS_FUNCAO,
        maxNestedCallbacks: config.ANALISE_LIMITES?.CODIGO_FRAGIL?.MAX_NESTED_CALLBACKS ?? LIMITES.CALLBACKS_ANINHADOS
    },
    visitor: visitorFragil,
    test: (relPath) => {
        if (/\.(deprecados?|abandonados?)\//i.test(relPath))
            return false;
        return /\.(js|jsx|ts|tsx|mjs|cjs)$/.test(relPath);
    },
    aplicar: (src, relPath, ast) => {
        if (!ast || !src)
            return [];
        const fragilidades = [];
        detectarLogsDebug(src).forEach(log => {
            fragilidades.push({
                tipo: 'console-log',
                linha: log.linha,
                coluna: 0,
                severidade: 'baixa',
                contexto: `console.${log.metodo} encontrado`
            });
        });
        detectarComentariosPendentes(src).forEach(todo => {
            fragilidades.push({
                tipo: 'todo-comment',
                linha: todo.linha,
                coluna: 0,
                severidade: 'baixa',
                contexto: `Comentário ${todo.tipo} encontrado: ${todo.texto.substring(0, 30)}...`
            });
        });
        const lines = splitLines(src);
        if (lines.length > LIMITES.MAX_LINHAS_ARQUIVO) {
            fragilidades.push({
                tipo: 'arquivo-muito-grande',
                linha: 1,
                coluna: 0,
                severidade: 'media',
                contexto: `Arquivo com ${lines.length} linhas (máx sugerido: ${LIMITES.MAX_LINHAS_ARQUIVO})`
            });
        }
        if (ast.preColetado) {
            fragilidades.push(...ast.preColetado);
        }
        else {
            const nodeToTraverse = ast.node || ast;
            const stateMock = {
                resultados: new Map([['codigo-fragil', []]])
            };
            traverse(nodeToTraverse, visitorFragil, undefined, stateMock);
            fragilidades.push(...(stateMock.resultados.get('codigo-fragil') || []));
        }
        detectarProblemasAvancados(src, fragilidades);
        const ocorrencias = [];
        const porSeveridade = agruparPor(fragilidades, arquivo => arquivo.severidade || 'media');
        for (const [severidade, items] of Object.entries(porSeveridade)) {
            if (items.length > 0) {
                const nivel = severidade === 'critica' || severidade === 'alta' ? 'erro' : severidade === 'media' ? 'aviso' : 'info';
                const resumo = items.slice(0, 3).map(caminho => caminho.tipo).join(', ');
                const tipos = {};
                for (const it of items) {
                    tipos[it.tipo] = (tipos[it.tipo] || 0) + 1;
                }
                const amostra = items.slice(0, 5).map(it => `${it.tipo} (L${it.linha})`);
                ocorrencias.push(criarOcorrencia({
                    tipo: 'codigo-fragil',
                    nivel,
                    mensagem: messages.DetectorCodigoFragilMensagens.fragilidadesResumo(severidade, resumo, {
                        severidade,
                        total: items.length,
                        tipos,
                        amostra
                    }),
                    relPath,
                    linha: items[0].linha
                }));
            }
        }
        return filtrarOcorrenciasSuprimidas(ocorrencias, 'codigo-fragil', src);
    }
};
function detectarProblemasAvancados(src, fragilidades) {
    const lines = splitLines(src);
    for (let indice = 0; indice < lines.length; indice++) {
        const line = lines[indice];
        if (/\.then\s*\(/.test(line) && !line.includes('.catch') && !src.split('\n')[indice + 1]?.includes('.catch')) {
            fragilidades.push({
                tipo: 'promise-sem-catch',
                linha: indice + 1,
                coluna: line.indexOf('.then'),
                severidade: 'media',
                contexto: 'Promise sem tratamento de erro (.catch)'
            });
        }
        const regexMatch = line.match(/\/([^\/\\]|\\.)+\/[gimuy]*/);
        if (regexMatch && regexMatch[0].length > LIMITES.REGEX_COMPLEXA_LENGTH && (regexMatch[0].match(/\(/g) || []).length > 3) {
            fragilidades.push({
                tipo: 'regex-complexa',
                linha: indice + 1,
                coluna: line.indexOf(regexMatch[0]),
                severidade: 'media',
                contexto: 'Regex complexa detectada'
            });
        }
    }
    detectarComplexidadeCognitiva(src, fragilidades);
}
function detectarComplexidadeCognitiva(src, fragilidades) {
    const lines = splitLines(src);
    let score = 0;
    let nesting = 0;
    for (let indice = 0; indice < lines.length; indice++) {
        const line = lines[indice].trim();
        if (/(if|while|for|switch|catch)/.test(line))
            score += 1 + nesting;
        if (line.includes('{'))
            nesting++;
        if (line.includes('}'))
            nesting--;
        if (score > LIMITES.COMPLEXIDADE_COGNITIVA) {
            fragilidades.push({
                tipo: 'complexidade-cognitiva',
                linha: indice + 1,
                coluna: 0,
                severidade: 'alta',
                contexto: `Complexidade cognitiva elevada (${score})`
            });
            score = 0;
        }
    }
}
function isSingleConsoleLog(stmt) {
    return stmt.type === 'ExpressionStatement' && stmt.expression?.type === 'CallExpression' && stmt.expression.callee?.type === 'MemberExpression' && stmt.expression.callee.object.name === 'console';
}
function isInVariableDeclarator(path) {
    return !!path.findParent(caminho => caminho.isVariableDeclarator());
}
function isInArrayIndex(path) {
    return !!path.findParent(caminho => caminho.isMemberExpression() && !!caminho.node.computed);
}
//# sourceMappingURL=detector-code-fragile.js.map