import { config, getAllExpectedDirNames, getDirVariantPattern, getNameConventions, isInsideSrc } from '../../core/config/index.js';
import { messages } from '../../core/messages/index.js';
import { detectarContextoProjeto } from '../../shared/index.js';
import micromatch from 'micromatch';
import { grafoDependencias } from './detector-dependencies.js';
export const sinaisDetectados = {};
export const detectorEstrutura = {
    nome: 'detector-estrutura',
    global: true,
    test(_relPath) {
        return true;
    },
    aplicar(_src, _relPath, _ast, _fullPath, contexto) {
        if (!contexto)
            return [];
        const caminhos = contexto.arquivos.map(arquivo => arquivo.relPath);
        const caminhosNorm = caminhos.map(caminho => caminho ? caminho.replace(/\\/g, '/') : '');
        const setCaminhos = new Set(caminhos);
        const arquivoPrincipal = caminhos?.find(caminho => /package\.json$/.test(caminho)) ?? caminhos?.[0] ?? '';
        const conteudoPrincipal = contexto.arquivos?.find(arquivo => arquivo.relPath === arquivoPrincipal)?.content || '';
        const contextoProjeto = detectarContextoProjeto({
            arquivo: arquivoPrincipal,
            conteudo: conteudoPrincipal,
            relPath: arquivoPrincipal
        });
        const isProjetoPequeno = caminhos.length < 20;
        const isProjetoTeste = contextoProjeto.isTest || caminhos.every(caminho => /(test|spec|mock)/i.test(caminho));
        const sinais = {
            temPages: caminhosNorm.some(caminho => caminho.includes('pages/') || caminho.includes('app/')),
            temApi: caminhosNorm.some(caminho => caminho.includes('api/')),
            temControllers: caminhosNorm.some(caminho => caminho.includes('controllers/')),
            temComponents: caminhosNorm.some(caminho => caminho.includes('components/')),
            temCli: caminhosNorm.some(caminho => /(^|\/)cli\.(ts|js)$/.test(caminho)),
            temSrc: caminhosNorm.some(caminho => isInsideSrc(caminho)),
            temPrisma: caminhosNorm.some(caminho => caminho.includes('prisma/') || caminho.includes('schema.prisma')),
            temPackages: caminhosNorm.some(caminho => caminho.includes('packages/') || caminho.includes('turbo.json')),
            temExpress: grafoDependencias.has('express')
        };
        const ehFullstack = !!(sinais.temPages && sinais.temApi && sinais.temPrisma);
        const ehMonorepo = !!sinais.temPackages;
        Object.assign(sinaisDetectados, sinais);
        const ocorrencias = [];
        if (ehMonorepo) {
            ocorrencias.push({
                tipo: 'estrutura-monorepo',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.monorepoDetectado,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
            if (!caminhos.some(caminho => caminho.includes('packages/'))) {
                ocorrencias.push({
                    tipo: 'estrutura-monorepo-incompleto',
                    nivel: 'aviso',
                    mensagem: messages.DetectorEstruturaMensagens.monorepoSemPackages,
                    origem: 'detector-estrutura',
                    relPath: '[raiz do projeto]',
                    linha: 0
                });
            }
        }
        if (ehFullstack) {
            ocorrencias.push({
                tipo: 'estrutura-fullstack',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.fullstackDetectado,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
        }
        else if (sinais.temPages && !sinais.temApi && !isProjetoPequeno) {
            ocorrencias.push({
                tipo: 'estrutura-incompleta',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.pagesSemApi,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
        }
        if (sinais.temSrc && sinais.temPackages && !contextoProjeto.isTest) {
            ocorrencias.push({
                tipo: 'estrutura-mista',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.estruturaMista,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
        }
        const arquivosRaiz = caminhosNorm.filter(caminho => !caminho.includes('/') && caminho.trim() !== '');
        const LIMITE_RAIZ = Number(config.ESTRUTURA_ARQUIVOS_RAIZ_MAX || 15);
        if (arquivosRaiz.length > LIMITE_RAIZ && !isProjetoPequeno && !isProjetoTeste) {
            ocorrencias.push({
                tipo: 'estrutura-suspeita',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.muitosArquivosRaiz,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
        }
        if (sinais.temControllers || sinais.temPrisma || sinais.temApi) {
            ocorrencias.push({
                tipo: 'estrutura-backend',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.sinaisBackend,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
        }
        if (sinais.temComponents || sinais.temPages) {
            ocorrencias.push({
                tipo: 'estrutura-frontend',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.sinaisFrontend,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
        }
        const arquivosConfiguracao = ['package.json', 'tsconfig.json', 'turbo.json', 'pnpm-workspace.yaml'];
        const detectados = arquivosConfiguracao.filter(cfg => setCaminhos.has(cfg));
        if (detectados.length > 0) {
            ocorrencias.push({
                tipo: 'estrutura-config',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.arquivosConfigDetectados(detectados),
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 1
            });
        }
        const entrypointsAll = caminhosNorm.filter(caminho => /(^|[\\/])(cli|index|main)\.(ts|js)$/.test(caminho));
        const ignoredDyn = config.INCLUDE_EXCLUDE_RULES && config.INCLUDE_EXCLUDE_RULES.globalExcludeGlob || [];
        const entrypoints = entrypointsAll.filter(caminho => !micromatch.isMatch(caminho, ignoredDyn || [])).sort();
        if (entrypoints.length > 1) {
            const MAX_LIST = 20;
            if (entrypoints.length > MAX_LIST) {
                const dirCounts = new Map();
                for (const caminho of entrypoints) {
                    const dir = caminho.includes('/') ? caminho.slice(0, caminho.lastIndexOf('/')) : '.';
                    dirCounts.set(dir, (dirCounts.get(dir) || 0) + 1);
                }
                const ordenado = [...dirCounts.entries()].sort((arquivo, base) => base[1] - arquivo[1] || (arquivo[0] < base[0] ? -1 : arquivo[0] > base[0] ? 1 : 0));
                const MAX_DIRS = 10;
                const top = ordenado.slice(0, MAX_DIRS);
                const ocultosDir = ordenado.length - top.length;
                const mostradosEntrypoints = top.reduce((acc, [, node]) => acc + node, 0);
                const ocultosEntrypoints = entrypoints.length - mostradosEntrypoints;
                const previewGrupos = top.map(([diretorio, node]) => `${diretorio} (${node})`).join(', ');
                const sufixoOcultos = [ocultosDir > 0 ? `+${ocultosDir} dirs` : null, ocultosEntrypoints > 0 ? `+${ocultosEntrypoints} entrypoints` : null].filter(Boolean).join(', ');
                ocorrencias.push({
                    tipo: 'estrutura-entrypoints',
                    nivel: 'aviso',
                    mensagem: messages.DetectorEstruturaMensagens.multiplosEntrypointsAgrupados({
                        previewGrupos,
                        sufixoOcultos
                    }),
                    origem: 'detector-estrutura',
                    relPath: '[raiz do projeto]',
                    linha: 0
                });
            }
            else {
                const preview = entrypoints.slice(0, MAX_LIST);
                const resto = entrypoints.length - preview.length;
                ocorrencias.push({
                    tipo: 'estrutura-entrypoints',
                    nivel: 'aviso',
                    mensagem: messages.DetectorEstruturaMensagens.multiplosEntrypointsLista(preview, resto),
                    origem: 'detector-estrutura',
                    relPath: '[raiz do projeto]',
                    linha: 0
                });
            }
        }
        const deveriaTerSrc = !contextoProjeto.isTest && !contextoProjeto.isConfiguracao && (contextoProjeto.isLibrary || contextoProjeto.frameworks.length > 0);
        if (!sinais.temSrc && caminhosNorm.length > 50 && deveriaTerSrc) {
            ocorrencias.push({
                tipo: 'estrutura-sem-src',
                nivel: 'info',
                mensagem: messages.DetectorEstruturaMensagens.projetoGrandeSemSrc,
                origem: 'detector-estrutura',
                relPath: '[raiz do projeto]',
                linha: 0
            });
        }
        const expectedDirs = getAllExpectedDirNames();
        if (expectedDirs.length > 0) {
            const topLevelDirs = new Set(caminhosNorm.filter(caminho => caminho.includes('/') && !caminho.startsWith('node_modules/') && !caminho.startsWith('dist/')).map(caminho => caminho.split('/')[0]));
            const configuredNames = new Set(Object.values(getNameConventions()).filter((valor) => typeof valor === 'string' && valor.trim().length > 0).map(valor => valor.trim().toLowerCase()));
            for (const { key, expected } of expectedDirs) {
                const expectedLower = expected.toLowerCase();
                const match = [...topLevelDirs].find(diretorio => diretorio.toLowerCase() === expectedLower);
                if (!match) {
                    const variantPattern = getDirVariantPattern(key);
                    const foundVariant = [...topLevelDirs].find(diretorio => variantPattern.test(diretorio));
                    if (foundVariant && !configuredNames.has(foundVariant.toLowerCase())) {
                        ocorrencias.push({
                            tipo: 'name-convention',
                            nivel: 'aviso',
                            mensagem: messages.DetectorEstruturaMensagens.nomeDiretorioNaoConforme(foundVariant, expected),
                            origem: 'detector-estrutura',
                            relPath: `[raiz do projeto]`,
                            linha: 0
                        });
                    }
                }
            }
        }
        return Array.isArray(ocorrencias) ? ocorrencias : [];
    }
};
//# sourceMappingURL=detector-structure.js.map