import fs from 'node:fs';
import path from 'node:path';
export function detectarMonorepo(baseDir) {
    const info = {
        isMonorepo: false,
        type: null,
        rootDir: baseDir,
        workspaces: [],
        packageManager: null,
    };
    const rootPkg = lerPackageJson(baseDir);
    if (!rootPkg)
        return info;
    const pm = rootPkg.packageManager || '';
    if (pm)
        info.packageManager = pm;
    let workspaceGlobs = [];
    const pnpmWorkspacePath = path.join(baseDir, 'pnpm-workspace.yaml');
    if (fs.existsSync(pnpmWorkspacePath)) {
        info.type = 'pnpm';
        try {
            const content = fs.readFileSync(pnpmWorkspacePath, 'utf-8');
            const match = content.match(/packages:\s*\n((?:\s+-\s+.*\n?)*)/);
            if (match) {
                workspaceGlobs = match[1].split('\n').map(l => l.trim().replace(/^- /, '')).filter(Boolean);
            }
        }
        catch { }
    }
    const lernaPath = path.join(baseDir, 'lerna.json');
    if (fs.existsSync(lernaPath)) {
        info.type = 'lerna';
        try {
            const lerna = JSON.parse(fs.readFileSync(lernaPath, 'utf-8'));
            if (lerna.packages && Array.isArray(lerna.packages)) {
                workspaceGlobs = lerna.packages;
            }
        }
        catch { }
    }
    const nxPath = path.join(baseDir, 'nx.json');
    if (fs.existsSync(nxPath)) {
        info.type = 'nx';
        try {
            const nx = JSON.parse(fs.readFileSync(nxPath, 'utf-8'));
            if (nx.workspaceLayout?.appsDir)
                workspaceGlobs.push(nx.workspaceLayout.appsDir);
            if (nx.workspaceLayout?.libsDir)
                workspaceGlobs.push(nx.workspaceLayout.libsDir);
        }
        catch { }
    }
    const turboPath = path.join(baseDir, 'turbo.json');
    if (fs.existsSync(turboPath)) {
        if (!info.type)
            info.type = 'turbo';
    }
    if (rootPkg.workspaces) {
        if (!info.type) {
            const detectedPm = info.packageManager || '';
            if (detectedPm.startsWith('yarn'))
                info.type = 'yarn-workspaces';
            else if (detectedPm.startsWith('pnpm'))
                info.type = 'pnpm';
            else
                info.type = 'npm-workspaces';
        }
        if (Array.isArray(rootPkg.workspaces)) {
            workspaceGlobs = rootPkg.workspaces;
        }
        else if (typeof rootPkg.workspaces === 'object' && rootPkg.workspaces !== null) {
            const ws = rootPkg.workspaces;
            if (Array.isArray(ws.packages)) {
                workspaceGlobs = ws.packages;
            }
        }
    }
    if (workspaceGlobs.length === 0 && info.type === 'turbo') {
        workspaceGlobs = ['apps/*', 'packages/*'];
    }
    if (workspaceGlobs.length > 0) {
        info.isMonorepo = true;
        info.workspaces = resolverWorkspaces(baseDir, workspaceGlobs);
    }
    return info;
}
function lerPackageJson(dir) {
    try {
        const pkgPath = path.join(dir, 'package.json');
        if (fs.existsSync(pkgPath)) {
            return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
        }
    }
    catch { }
    return null;
}
function resolverWorkspaces(rootDir, globs) {
    const workspaces = [];
    const seen = new Set();
    for (const glob of globs) {
        const baseDir = glob.replace(/\/\*$/, '').replace(/\/\*\*$/, '');
        const fullPath = path.join(rootDir, baseDir);
        if (fs.existsSync(fullPath)) {
            try {
                const entries = fs.readdirSync(fullPath, { withFileTypes: true });
                for (const entry of entries) {
                    if (entry.isDirectory() && !entry.name.startsWith('.')) {
                        const wsDir = path.join(fullPath, entry.name);
                        const resolved = path.resolve(wsDir);
                        if (seen.has(resolved))
                            continue;
                        seen.add(resolved);
                        const pkg = lerPackageJson(wsDir);
                        if (pkg) {
                            workspaces.push({
                                name: pkg.name || entry.name,
                                dir: resolved,
                                packageJson: pkg,
                                dependencies: pkg.dependencies || {},
                                devDependencies: pkg.devDependencies || {},
                                peerDependencies: pkg.peerDependencies || {},
                            });
                        }
                    }
                }
            }
            catch { }
        }
    }
    return workspaces;
}
export const detectorMonorepo = {
    nome: 'detector-monorepo',
    global: true,
    test(_relPath) {
        return true;
    },
    aplicar(_src, _relPath, _ast, _fullPath, contexto) {
        if (!contexto)
            return [];
        const baseDir = contexto.baseDir;
        const info = detectarMonorepo(baseDir);
        if (!info.isMonorepo)
            return [];
        const ocorrencias = [];
        ocorrencias.push({
            tipo: 'monorepo-detectado',
            nivel: 'info',
            mensagem: `Monorepo detectado: ${info.type ?? 'desconhecido'} (${info.workspaces.length} workspaces)`,
            origem: 'detector-monorepo',
            relPath: '[monorepo]',
            linha: 0,
        });
        const rootPkg = lerPackageJson(baseDir);
        if (rootPkg) {
            const scripts = rootPkg.scripts || {};
            const expectedScripts = ['build', 'test', 'lint'];
            for (const script of expectedScripts) {
                if (!scripts[script]) {
                    ocorrencias.push({
                        tipo: 'monorepo-root-script-ausente',
                        nivel: 'aviso',
                        mensagem: `Workspace root missing script: ${script}`,
                        origem: 'detector-monorepo',
                        relPath: 'package.json',
                        linha: 0,
                    });
                }
            }
        }
        for (const ws of info.workspaces) {
            const relDir = path.relative(baseDir, ws.dir);
            if (!ws.packageJson?.name) {
                ocorrencias.push({
                    tipo: 'monorepo-workspace-sem-nome',
                    nivel: 'aviso',
                    mensagem: `Workspace sem nome: ${relDir}`,
                    origem: 'detector-monorepo',
                    relPath: path.join(relDir, 'package.json'),
                    linha: 0,
                });
            }
            if (!ws.packageJson?.version) {
                ocorrencias.push({
                    tipo: 'monorepo-workspace-sem-versao',
                    nivel: 'info',
                    mensagem: `Workspace sem versão: ${ws.name} (${relDir})`,
                    origem: 'detector-monorepo',
                    relPath: path.join(relDir, 'package.json'),
                    linha: 0,
                });
            }
        }
        const allDeps = new Map();
        for (const ws of info.workspaces) {
            const deps = new Set([
                ...Object.keys(ws.dependencies),
                ...Object.keys(ws.devDependencies),
                ...Object.keys(ws.peerDependencies),
            ]);
            for (const dep of deps) {
                const depSet = allDeps.get(dep) ?? new Set();
                depSet.add(ws.name);
                allDeps.set(dep, depSet);
            }
        }
        const versionMap = new Map();
        for (const ws of info.workspaces) {
            for (const [dep, ver] of Object.entries(ws.dependencies)) {
                const verMap = versionMap.get(dep) ?? new Map();
                verMap.set(ws.name, ver);
                versionMap.set(dep, verMap);
            }
        }
        for (const [dep, versions] of versionMap) {
            if (versions.size > 1) {
                const uniqueVersions = new Set(versions.values());
                if (uniqueVersions.size > 1) {
                    ocorrencias.push({
                        tipo: 'monorepo-versao-mismatch',
                        nivel: 'aviso',
                        mensagem: `Dependência ${dep} com versões diferentes entre workspaces: ${Array.from(versions.entries()).map(([w, v]) => `${w}@${v}`).join(', ')}`,
                        origem: 'detector-monorepo',
                        relPath: '[monorepo]',
                        linha: 0,
                    });
                }
            }
        }
        const workspaceNames = new Set(info.workspaces.map(w => w.name));
        for (const ws of info.workspaces) {
            const imports = coletarImports(ws.dir);
            for (const imp of imports) {
                for (const wsName of workspaceNames) {
                    if (imp.includes(wsName) && wsName !== ws.name) {
                        const isDep = ws.dependencies[wsName] || ws.devDependencies[wsName] || ws.peerDependencies[wsName];
                        if (!isDep) {
                            ocorrencias.push({
                                tipo: 'monorepo-dependencia-interna-faltando',
                                nivel: 'aviso',
                                mensagem: `${ws.name} importa ${wsName} mas não o declara como dependência`,
                                origem: 'detector-monorepo',
                                relPath: `[${ws.name}]`,
                                linha: 0,
                            });
                        }
                        break;
                    }
                }
            }
        }
        return ocorrencias;
    },
};
function coletarImports(dir) {
    const imports = [];
    try {
        const files = fs.readdirSync(dir, { recursive: true });
        for (const file of files) {
            if (/\.(ts|js|tsx|jsx|mjs)$/.test(file)) {
                try {
                    const content = fs.readFileSync(path.join(dir, file), 'utf-8');
                    const importMatches = content.matchAll(/from\s+['"]([^'"]+)['"]/g);
                    for (const m of importMatches) {
                        imports.push(m[1]);
                    }
                    const requireMatches = content.matchAll(/require\(['"]([^'"]+)['"]\)/g);
                    for (const m of requireMatches) {
                        imports.push(m[1]);
                    }
                }
                catch { }
            }
        }
    }
    catch { }
    return imports;
}
//# sourceMappingURL=detector-monorepo.js.map