import { traverse } from '../../core/config/index.js';
import { messages } from '../../core/messages/index.js';
import { detectarContextoProjeto } from '../../shared/index.js';
import { agruparPor, criarErroAnalise, filtrarOcorrenciasSuprimidas, splitLines } from '../../shared/helpers/index.js';
import { criarOcorrencia } from '../../types/index.js';
export const analistaDesempenho = {
    nome: 'performance',
    categoria: 'performance',
    descricao: 'Detecta problemas de performance e otimizações possíveis',
    test: (relPath) => {
        return /\.(js|jsx|ts|tsx|mjs|cjs)$/.test(relPath);
    },
    aplicar: (src, relPath, ast) => {
        if (!src)
            return [];
        const contextoArquivo = detectarContextoProjeto({
            arquivo: relPath,
            conteudo: src,
            relPath
        });
        const problemas = [];
        try {
            detectarPadroesPerformance(src, problemas, relPath);
            if (ast) {
                detectarProblemasPerformanceAST(ast, problemas, relPath);
            }
            const ocorrencias = [];
            const porImpacto = agruparPor(problemas, caminho => caminho.impacto || 'medio');
            for (const [impacto, items] of Object.entries(porImpacto)) {
                if (items.length > 0) {
                    const nivel = mapearImpactoParaNivel(impacto);
                    const nivelAjustado = contextoArquivo.isTest && nivel === 'aviso' ? 'info' : nivel;
                    const resumo = items.slice(0, 3).map(caminho => caminho.tipo).join(', ');
                    ocorrencias.push(criarOcorrencia({
                        tipo: 'PROBLEMA_PERFORMANCE',
                        nivel: nivelAjustado,
                        mensagem: messages.DetectorAgregadosMensagens.problemasPerformanceResumo(impacto, resumo, items.length),
                        relPath,
                        linha: items[0].linha
                    }));
                }
            }
            return filtrarOcorrenciasSuprimidas(ocorrencias, 'performance', src);
        }
        catch (erro) {
            return [criarErroAnalise(relPath, messages.DetectorAgregadosMensagens.erroAnalisarPerformance(erro))];
        }
    }
};
function detectarPadroesPerformance(src, problemas, relPath) {
    const linhas = splitLines(src);
    let dentroLoop = 0;
    const loopOpen = /\b(for|while)\s*\(/;
    const loopClose = /^\s*\}/;
    linhas.forEach((linha, index) => {
        const numeroLinha = index + 1;
        if (loopOpen.test(linha))
            dentroLoop++;
        if (loopClose.test(linha) && dentroLoop > 0)
            dentroLoop--;
        if (/\b(readFileSync|writeFileSync|execSync)\s*\(/.test(linha)) {
            problemas.push({
                tipo: 'blocking-operation',
                descricao: 'Operação síncrona pode bloquear event loop',
                impacto: 'alto',
                linha: numeroLinha,
                coluna: linha.indexOf(/readFileSync|writeFileSync|execSync/.exec(linha)?.[0] || '') + 1,
                sugestao: 'Use versões assíncronas: readFile, writeFile, exec'
            });
        }
        if (/addEventListener\s*\(/.test(linha)) {
            const srcSemComentarios = src.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
            if (!srcSemComentarios.includes('removeEventListener') && !srcSemComentarios.includes('cleanup') && !srcSemComentarios.includes('destroy')) {
                problemas.push({
                    tipo: 'memory-leak',
                    descricao: 'Event listener pode causar vazamento de memória',
                    impacto: 'medio',
                    linha: numeroLinha,
                    coluna: linha.indexOf('addEventListener') + 1,
                    sugestao: 'Adicione removeEventListener em cleanup/destroy'
                });
            }
        }
        if (/\.map\s*\([^)]*\)/.test(linha) && (/return\s*<|<\w+/.test(linha) || relPath.includes('.tsx') || relPath.includes('.jsx')) && !linha.includes('key=')) {
            problemas.push({
                tipo: 'unnecessary-rerender',
                descricao: 'React map sem key prop pode causar rerenders desnecessários',
                impacto: 'medio',
                linha: numeroLinha,
                coluna: linha.indexOf('.map') + 1,
                sugestao: 'Adicione key prop única para cada elemento da lista'
            });
        }
        if (/\.forEach\s*\(.*\.(find|get|query|select)\s*\(/.test(linha)) {
            problemas.push({
                tipo: 'n-plus-one',
                descricao: 'Possível problema N+1 em consultas',
                impacto: 'alto',
                linha: numeroLinha,
                coluna: linha.indexOf('.forEach') + 1,
                sugestao: 'Use join/include ou agrupe consultas para evitar N+1'
            });
        }
        if (/\bawait\b/.test(linha) && dentroLoop > 0) {
            problemas.push({
                tipo: 'sequential-await',
                descricao: 'Await dentro de loop executa operações sequencialmente',
                impacto: 'medio',
                linha: numeroLinha,
                coluna: linha.indexOf('await') + 1,
                sugestao: 'Considere usar Promise.all() para executar em paralelo'
            });
        }
        if (/\.\.\./.test(linha) && dentroLoop > 0 && /\{.*\.{3}.*\}/.test(linha)) {
            problemas.push({
                tipo: 'expensive-spread',
                descricao: 'Spread de objeto em loop pode ser custoso em termos de memória e CPU',
                impacto: 'medio',
                linha: numeroLinha,
                coluna: linha.indexOf('...') + 1,
                sugestao: 'Considere mutar um objeto local ou usar Map se o objeto for grande'
            });
        }
        if (relPath.endsWith('.tsx') || relPath.endsWith('.jsx')) {
            if (/const\s+\w+\s*=\s*\[.*\]|const\s+\w+\s*=\s*\{.*\}|const\s+\w+\s*=\s*\(.*\)\s*=>/.test(linha) && !/useMemo|useCallback/.test(linha) && !/^\s*\/\//.test(linha)) {
                const totalLinhas = linhas.length;
                const contextoPosterior = linhas.slice(index, Math.min(index + 20, totalLinhas)).join('\n');
                if (/<[A-Z]|return\s*\(?\s*</.test(contextoPosterior)) {
                    problemas.push({
                        tipo: 'missing-memoization',
                        descricao: 'Objeto/função criado a cada render sem useMemo/useCallback',
                        impacto: 'baixo',
                        linha: numeroLinha,
                        coluna: 1,
                        sugestao: 'Envolva em useMemo ou useCallback para evitar re-renders desnecessários de componentes filhos'
                    });
                }
            }
        }
        if (/import.*from\s+['"]lodash['"]|import.*from\s+['"]moment['"]/.test(linha)) {
            problemas.push({
                tipo: 'large-bundle',
                descricao: 'Import completo de biblioteca grande pode aumentar bundle',
                impacto: 'medio',
                linha: numeroLinha,
                coluna: linha.indexOf('import') + 1,
                sugestao: 'Use imports específicos: import { method } from "lodash/method"'
            });
        }
    });
}
function detectarProblemasPerformanceAST(ast, problemas, relPath) {
    try {
        const isLoop = (type) => ['ForStatement', 'WhileStatement', 'DoWhileStatement', 'ForInStatement', 'ForOfStatement'].includes(type);
        const checkNesting = (path) => {
            let parent = path.parentPath;
            while (parent) {
                if (isLoop(parent.type)) {
                    problemas.push({
                        tipo: 'inefficient-loop',
                        descricao: 'Loop aninhado detectado via AST - pode causar performance O(n2)',
                        impacto: 'alto',
                        linha: path.node.loc?.start.line || 0,
                        coluna: path.node.loc?.start.column || 0,
                        sugestao: 'Considere usar Map, Set ou otimizar algoritmo para complexidade linear'
                    });
                    break;
                }
                parent = parent.parentPath;
            }
        };
        traverse(ast.node, {
            ForStatement: checkNesting,
            WhileStatement: checkNesting,
            DoWhileStatement: checkNesting,
            ForInStatement: checkNesting,
            ForOfStatement: checkNesting,
            CallExpression(path) {
                if (path.node.callee.type === 'Identifier' && (path.node.callee.name === 'setTimeout' || path.node.callee.name === 'setInterval')) {
                    const parentFunction = path.getFunctionParent();
                    const context = parentFunction ? parentFunction.toString() : ast.toString();
                    if (!context.includes('clear') && !relPath.includes('test')) {
                        problemas.push({
                            tipo: 'memory-leak',
                            descricao: `${path.node.callee.name} sem cleanup pode causar vazamento`,
                            impacto: 'medio',
                            linha: path.node.loc?.start.line || 0,
                            coluna: path.node.loc?.start.column || 0,
                            sugestao: `Use clear${path.node.callee.name.replace('set', '')} para limpar`
                        });
                    }
                }
            }
        });
    }
    catch {
    }
}
function mapearImpactoParaNivel(impacto) {
    switch (impacto) {
        case 'alto':
            return 'aviso';
        case 'medio':
            return 'aviso';
        case 'baixo':
        default:
            return 'info';
    }
}
//# sourceMappingURL=detector-performance.js.map