import { existsSync, promises as fsAsync, readdirSync } from 'node:fs';
import path from 'node:path';
import { getMessages } from '../../core/messages/index.js';
import { normalizePath } from '../../shared/helpers/index.js';
const { log } = getMessages();
const SKIP_DIRS = new Set(['node_modules', 'dist', 'coverage', '.git', '.deprecados', '.tutanus']);
const EXT_PATTERN = /\.(ts|tsx|js|jsx|mjs|cjs)$/;
function normalizarRel(caminho) {
    return path.posix.normalize(normalizePath(caminho).replace(/\\/g, '/'));
}
function semExt(caminho) {
    return caminho.replace(EXT_PATTERN, '');
}
function resolverImportRelativo(arquivoRel, importSpec) {
    const dir = path.posix.dirname(normalizarRel(arquivoRel));
    return path.posix.normalize(path.posix.join(dir, importSpec));
}
function criarMapaMovimentos(mapa, _baseDir) {
    const movimentos = new Map();
    for (const entry of mapa) {
        if (!entry.ideal || entry.ideal === entry.atual)
            continue;
        const nomeArquivo = path.basename(entry.arquivo);
        const origemRel = normalizarRel(entry.arquivo.replace(/^src\//, ''));
        const destinoRel = normalizarRel(path.posix.join(entry.ideal.replace(/^src\//, ''), nomeArquivo));
        if (origemRel !== destinoRel) {
            movimentos.set(semExt(origemRel), semExt(destinoRel));
        }
    }
    return movimentos;
}
async function* walkDir(dir) {
    try {
        const entries = await fsAsync.readdir(dir, { withFileTypes: true });
        for (const entry of entries) {
            const full = path.join(dir, entry.name);
            if (entry.isDirectory()) {
                if (SKIP_DIRS.has(entry.name))
                    continue;
                yield* walkDir(full);
            }
            else if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx'))) {
                yield full;
            }
        }
    }
    catch {
    }
}
function ehBarrel(content) {
    return /export\s+.*?\s+from\s+['"]/.test(content);
}
async function encontrarBarrels(srcDir) {
    const barrels = [];
    for await (const filePath of walkDir(srcDir)) {
        if (path.basename(filePath) !== 'index.ts')
            continue;
        try {
            const content = await fsAsync.readFile(filePath, 'utf-8');
            if (ehBarrel(content)) {
                barrels.push(normalizarRel(path.relative(srcDir, filePath).replace(/\\/g, '/')));
            }
        }
        catch {
        }
    }
    return barrels;
}
function analisarExport(linha, barrelRel, movimentos) {
    const trimmed = linha.trim();
    if (!trimmed.startsWith('export') || !trimmed.includes('from')) {
        return { exportSpec: null, exportInfo: null };
    }
    const PADRAO = /export\s+(?:\*\s+from|(?:default\s+|type\s+)?\{[^}]*\}\s+from)\s+['"]([^'"]+)['"]\s*;?\s*$/;
    const match = PADRAO.exec(linha);
    if (!match)
        return { exportSpec: null, exportInfo: null };
    const spec = match[1];
    if (!spec.startsWith('.'))
        return { exportSpec: spec, exportInfo: null };
    const resolved = semExt(resolverImportRelativo(barrelRel, spec));
    const moveDest = movimentos.get(resolved) ?? null;
    return { exportSpec: spec, exportInfo: { spec, resolved, moveDest } };
}
function temMoveDest(e) {
    return e.moveDest !== null;
}
function analisarBarrel(content, barrelRel, movimentos) {
    const exports = [];
    const linhas = content.split('\n');
    for (const linha of linhas) {
        const { exportInfo } = analisarExport(linha, barrelRel, movimentos);
        if (exportInfo)
            exports.push(exportInfo);
    }
    const movidos = exports.filter(temMoveDest);
    const ficaram = exports.filter(e => e.moveDest === null);
    const todosMovidos = exports.length > 0 && movidos.length === exports.length;
    let dirDestinoUnico = null;
    if (todosMovidos) {
        const dirs = new Set(movidos.map(e => path.posix.dirname(e.moveDest)));
        if (dirs.size === 1) {
            const val = dirs.values().next().value;
            if (val !== undefined)
                dirDestinoUnico = val;
        }
    }
    return { barrelRel, exports, movidos, ficaram, todosMovidos, dirDestinoUnico };
}
function removerExportsMovidos(content, barrelRel, movimentos) {
    const linhas = content.split('\n');
    const resultado = [];
    for (const linha of linhas) {
        const { exportSpec, exportInfo } = analisarExport(linha, barrelRel, movimentos);
        if (exportInfo && exportInfo.moveDest !== null)
            continue;
        if (exportSpec !== null && exportInfo === null) {
            resultado.push(linha);
            continue;
        }
        if (!exportInfo) {
            resultado.push(linha);
            continue;
        }
        resultado.push(linha);
    }
    return resultado.join('\n');
}
async function moverBarrel(barrelRel, dirDestino, srcDir) {
    const origemAbs = path.join(srcDir, barrelRel);
    const nomeArquivo = path.basename(barrelRel);
    const destinoAbs = path.join(srcDir, dirDestino, nomeArquivo);
    const destinoDirAbs = path.dirname(destinoAbs);
    try {
        await fsAsync.mkdir(destinoDirAbs, { recursive: true });
        await fsAsync.rename(origemAbs, destinoAbs);
        log.info(`Barrel movido: ${barrelRel} → ${path.posix.join(dirDestino, nomeArquivo)}`);
    }
    catch (err) {
        log.aviso(`Erro ao mover barrel ${barrelRel}: ${err instanceof Error ? err.message : String(err)}`);
    }
}
async function criarBarrelSeNecessario(dirRel, exportsParaAdicionar, srcDir) {
    const barrelPath = path.join(srcDir, dirRel, 'index.ts');
    if (exportsParaAdicionar.length === 0)
        return false;
    const linhas = [];
    if (existsSync(barrelPath)) {
        const content = await fsAsync.readFile(barrelPath, 'utf-8');
        linhas.push(content.replace(/\n$/, ''));
    }
    for (const exp of exportsParaAdicionar) {
        const moveDest = exp.moveDest;
        if (!moveDest)
            continue;
        const nomeArquivo = path.basename(moveDest);
        linhas.push(`export * from './${nomeArquivo}.js';`);
    }
    const novoConteudo = `${linhas.join('\n')}\n`;
    try {
        await fsAsync.mkdir(path.dirname(barrelPath), { recursive: true });
        await fsAsync.writeFile(barrelPath, novoConteudo, 'utf-8');
        const relPath = path.relative(srcDir, barrelPath);
        log.info(`Barrel ${existsSync(barrelPath) ? 'atualizado' : 'criado'}: ${relPath}`);
        return true;
    }
    catch {
        return false;
    }
}
async function apagarBarrelSeVazio(barrelRel, srcDir) {
    const barrelAbs = path.join(srcDir, barrelRel);
    try {
        const content = await fsAsync.readFile(barrelAbs, 'utf-8');
        const trimmed = content.trim();
        if (!trimmed || !ehBarrel(trimmed)) {
            await fsAsync.unlink(barrelAbs);
            log.info(`Barrel vazio removido: ${barrelRel}`);
            return true;
        }
    }
    catch {
    }
    return false;
}
async function atualizarImportsGlobais(srcDir, movimentos) {
    let totalReescritos = 0;
    for await (const filePath of walkDir(srcDir)) {
        const rel = normalizarRel(path.relative(srcDir, filePath).replace(/\\/g, '/'));
        try {
            const content = await fsAsync.readFile(filePath, 'utf-8');
            let reescritos = 0;
            const linhas = content.split('\n');
            for (let i = 0; i < linhas.length; i++) {
                const linha = linhas[i];
                const trimmed = linha.trim();
                if (!trimmed.startsWith('import') && !trimmed.startsWith('export') && !trimmed.includes('require('))
                    continue;
                const matches = linha.matchAll(/(['"])([^'"\n]+?)\1/g);
                for (const m of matches) {
                    const spec = m[2];
                    if (!spec)
                        continue;
                    const isRelative = spec.startsWith('./') || spec.startsWith('../');
                    const isAlias = spec.startsWith('@/') || /^@[^/]+\//.test(spec);
                    if (!isRelative && !isAlias)
                        continue;
                    let resolved;
                    if (spec.startsWith('@/')) {
                        resolved = semExt(normalizarRel(`src/${spec.slice(2)}`));
                    }
                    else if (spec.startsWith('@')) {
                        resolved = semExt(normalizarRel(`src/${spec.slice(1)}`)).replace(/^src\//, '');
                    }
                    else {
                        resolved = semExt(resolverImportRelativo(rel, spec));
                    }
                    const moveDestino = movimentos.get(resolved);
                    if (!moveDestino)
                        continue;
                    const fileDir = path.posix.dirname(rel);
                    let newSpec = path.posix.relative(fileDir, moveDestino);
                    newSpec = normalizarRel(newSpec);
                    if (!newSpec.startsWith('.'))
                        newSpec = `./${newSpec}`;
                    const ext = path.extname(spec);
                    if (ext === '.js' || ext === '.mjs' || ext === '.cjs') {
                        newSpec += ext;
                    }
                    else if (!path.extname(newSpec)) {
                        newSpec += '.js';
                    }
                    const escapedOld = spec.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
                    const fromRegex = new RegExp(`(['\"])${escapedOld}\\1`);
                    if (fromRegex.test(linhas[i])) {
                        linhas[i] = linhas[i].replace(fromRegex, `$1${newSpec}$1`);
                        reescritos++;
                    }
                }
            }
            if (reescritos > 0) {
                await fsAsync.writeFile(filePath, linhas.join('\n'), 'utf-8');
                totalReescritos += reescritos;
            }
        }
        catch {
        }
    }
    return totalReescritos;
}
async function extrairNomesExportados(srcDir, relPath, visitados = new Set(), profundidade = 0) {
    if (profundidade > 5)
        return new Set();
    const caminho = path.join(srcDir, relPath);
    const chave = normalizarRel(relPath);
    if (visitados.has(chave))
        return new Set();
    visitados.add(chave);
    const nomes = new Set();
    try {
        const content = await fsAsync.readFile(caminho, 'utf-8');
        for (const linha of content.split('\n')) {
            const trimmed = linha.trim();
            if (trimmed.startsWith('export default ')) {
                nomes.add('default');
            }
            const exportDecl = trimmed.match(/^export\s+(?:type\s+)?(?:(?:async\s+)?(?:function|const|let|var|class|interface|type|enum))\s+(\w+)/);
            if (exportDecl && exportDecl[1]) {
                nomes.add(exportDecl[1]);
            }
            const exportList = trimmed.match(/^export\s+type\s*\{([^}]+)\}|^export\s*\{([^}]+)\}/);
            if (exportList) {
                const body = exportList[1] ?? exportList[2];
                if (body) {
                    body.split(',').forEach(part => {
                        const m = part.trim().match(/^(\w+)(?:\s+as\s+\w+)?$/);
                        if (m)
                            nomes.add(m[1]);
                    });
                }
            }
            const reexportMatch = trimmed.match(/^export\s+(?:type\s+)?\*\s+from\s+['"]([^'"]+)['"]/);
            if (reexportMatch) {
                const resolved = resolverImportRelativo(relPath, reexportMatch[1]);
                const resolvedPath = `${semExt(resolved)}.ts`;
                const subNomes = await extrairNomesExportados(srcDir, resolvedPath, visitados, profundidade + 1);
                for (const n of subNomes)
                    nomes.add(n);
            }
        }
    }
    catch {
    }
    return nomes;
}
function classificarExports(content) {
    const types = new Set();
    const values = new Set();
    for (const linha of content.split('\n')) {
        const trimmed = linha.trim();
        if (!trimmed.startsWith('export'))
            continue;
        if (/from\s+['"]/.test(trimmed))
            continue;
        let m = trimmed.match(/^export\s+interface\s+(\w+)/);
        if (m) {
            types.add(m[1]);
            continue;
        }
        if (/^export\s+type\s+(\w+)\s*=/.test(trimmed)) {
            m = trimmed.match(/^export\s+type\s+(\w+)\s*=/);
            if (m) {
                types.add(m[1]);
                continue;
            }
        }
        m = trimmed.match(/^export\s+enum\s+(\w+)/);
        if (m) {
            values.add(m[1]);
            continue;
        }
        m = trimmed.match(/^export\s+default\s+(?:abstract\s+)?(?:class|function)\s+(\w+)/);
        if (m) {
            values.add(m[1]);
            continue;
        }
        if (/^export\s+default\s+/.test(trimmed)) {
            continue;
        }
        m = trimmed.match(/^export\s+(?:abstract\s+)?(?:async\s+)?(?:function|const|let|var|class)\s+(\w+)/);
        if (m) {
            values.add(m[1]);
            continue;
        }
        m = trimmed.match(/^export\s+(?:type\s+)?\{([^}]+)\}/);
        if (m) {
            m[1].split(',').forEach(part => {
                const name = part.trim().match(/^(\w+)/);
                if (name)
                    values.add(name[1]);
            });
            continue;
        }
    }
    return { types, values };
}
async function repararImportsBarrelPerdidos(srcDir, barrelsPerdidos, _movimentos) {
    if (barrelsPerdidos.size === 0)
        return 0;
    let totalReparados = 0;
    const nomeParaDestino = new Map();
    for (const [, perdas] of barrelsPerdidos) {
        for (const [, dest] of perdas) {
            if (nomeParaDestino.has(dest))
                continue;
            const destPath = `${semExt(dest)}.ts`;
            const nomes = await extrairNomesExportados(srcDir, destPath);
            for (const nome of nomes) {
                if (!nomeParaDestino.has(nome)) {
                    nomeParaDestino.set(nome, dest);
                }
            }
        }
    }
    for (const [barrelRel, perdas] of barrelsPerdidos) {
        if (perdas.size === 0)
            continue;
        const barrelAliasCandidates = new Set();
        barrelAliasCandidates.add(barrelRel.replace(/\/index\.ts$/, ''));
        barrelAliasCandidates.add(barrelRel.replace(/\.ts$/, ''));
        barrelAliasCandidates.add(barrelRel);
        for await (const filePath of walkDir(srcDir)) {
            const rel = normalizarRel(path.relative(srcDir, filePath).replace(/\\/g, '/'));
            if (rel === barrelRel)
                continue;
            try {
                const content = await fsAsync.readFile(filePath, 'utf-8');
                const linhas = content.split('\n');
                let mudou = false;
                for (let i = 0; i < linhas.length; i++) {
                    const linha = linhas[i];
                    const trimmed = linha.trim();
                    const importMatch = trimmed.match(/^(import|export)\s+(?:type\s+)?(?:\{([^}]*)\})\s+from\s+['"]([^'"]+)['"]/);
                    if (!importMatch)
                        continue;
                    const [, keyword, namesRaw, spec] = importMatch;
                    if (!spec || !namesRaw)
                        continue;
                    let resolvedSpec;
                    if (spec.startsWith('.')) {
                        resolvedSpec = semExt(resolverImportRelativo(rel, spec));
                    }
                    else if (spec.startsWith('@/')) {
                        resolvedSpec = semExt(normalizarRel(`src/${spec.slice(2)}`));
                    }
                    else if (spec.startsWith('@')) {
                        resolvedSpec = semExt(normalizarRel(`src/${spec.slice(1)}`)).replace(/^src\//, '');
                    }
                    else {
                        continue;
                    }
                    if (!barrelAliasCandidates.has(resolvedSpec))
                        continue;
                    const nomes = namesRaw.split(',').map(n => {
                        const match = n.trim().match(/^(?:type\s+)?(\w+)(?:\s+as\s+(\w+))?/);
                        if (!match)
                            return null;
                        return { imported: match[1], local: match[2] ?? match[1] };
                    }).filter((n) => n !== null);
                    const nomesQueFicam = [];
                    const nomesQueMoveram = [];
                    for (const nome of nomes) {
                        const dest = nomeParaDestino.get(nome.imported);
                        if (dest) {
                            nomesQueMoveram.push({ ...nome, dest });
                        }
                        else {
                            nomesQueFicam.push(nome);
                        }
                    }
                    if (nomesQueMoveram.length === 0)
                        continue;
                    const isTypeOnly = trimmed.includes('import type {') || trimmed.includes('export type {');
                    if (nomesQueFicam.length > 0) {
                        const nomesStr = nomesQueFicam.map(n => n.imported !== n.local ? `${n.imported} as ${n.local}` : n.imported).join(', ');
                        const typePrefix = isTypeOnly ? 'type ' : '';
                        linhas[i] = `${keyword} ${typePrefix}{ ${nomesStr} } from '${spec}';`;
                    }
                    else {
                        linhas[i] = '';
                    }
                    const fileDir = path.posix.dirname(rel);
                    const novasLinhas = [];
                    for (const nome of nomesQueMoveram) {
                        let newSpec = path.posix.relative(fileDir, nome.dest);
                        newSpec = normalizarRel(newSpec);
                        if (!newSpec.startsWith('.'))
                            newSpec = `./${newSpec}`;
                        if (!path.extname(newSpec))
                            newSpec += '.js';
                        const typePrefix = isTypeOnly ? 'import type' : 'import';
                        if (nome.imported !== nome.local) {
                            novasLinhas.push(`${typePrefix} { ${nome.imported} as ${nome.local} } from '${newSpec}';`);
                        }
                        else {
                            novasLinhas.push(`${typePrefix} { ${nome.imported} } from '${newSpec}';`);
                        }
                    }
                    if (novasLinhas.length > 0) {
                        linhas.splice(i + 1, 0, ...novasLinhas);
                        i += novasLinhas.length;
                    }
                    mudou = true;
                    totalReparados++;
                }
                if (mudou) {
                    const linhasLimpar = linhas.filter(l => l !== '');
                    await fsAsync.writeFile(filePath, linhasLimpar.join('\n'), 'utf-8');
                }
            }
            catch {
            }
        }
    }
    return totalReparados;
}
export async function reorganizarBarrelsAposMovimento(baseDir, mapa) {
    const srcDir = path.join(baseDir, 'src');
    const movimentos = criarMapaMovimentos(mapa, baseDir);
    if (movimentos.size === 0)
        return;
    log.info('Reorganizando barrels e atualizando imports após movimentação...');
    const barris = await encontrarBarrels(srcDir);
    const mapDestinos = new Map();
    const barrelsPerdidos = new Map();
    let barrisMovidos = 0;
    let barrisModificados = 0;
    let barrisCriados = 0;
    let barrisRemovidos = 0;
    for (const barrelRel of barris) {
        let content;
        try {
            content = await fsAsync.readFile(path.join(srcDir, barrelRel), 'utf-8');
        }
        catch {
            continue;
        }
        const analise = analisarBarrel(content, barrelRel, movimentos);
        if (!analise.todosMovidos && analise.movidos.length === 0)
            continue;
        if (analise.todosMovidos && analise.dirDestinoUnico) {
            const nomeBarrel = path.basename(barrelRel);
            const novoBarrelRel = path.posix.join(analise.dirDestinoUnico, nomeBarrel);
            const destBarrelAbs = path.join(srcDir, novoBarrelRel);
            if (!existsSync(destBarrelAbs)) {
                await moverBarrel(barrelRel, analise.dirDestinoUnico, srcDir);
                barrisMovidos++;
                movimentos.set(semExt(barrelRel), semExt(novoBarrelRel));
                continue;
            }
        }
        if (analise.movidos.length > 0) {
            const novoConteudo = removerExportsMovidos(content, barrelRel, movimentos);
            await fsAsync.writeFile(path.join(srcDir, barrelRel), novoConteudo, 'utf-8');
            barrisModificados++;
            log.info(`Barrel atualizado (exports removidos): ${barrelRel}`);
            const perdas = new Map();
            for (const exp of analise.movidos) {
                perdas.set(exp.resolved, exp.moveDest);
            }
            barrelsPerdidos.set(barrelRel, perdas);
            for (const exp of analise.movidos) {
                const dirDest = path.posix.dirname(exp.moveDest);
                const lista = mapDestinos.get(dirDest);
                if (lista) {
                    lista.push(exp);
                }
                else {
                    mapDestinos.set(dirDest, [exp]);
                }
            }
            const vazio = await apagarBarrelSeVazio(barrelRel, srcDir);
            if (vazio)
                barrisRemovidos++;
        }
    }
    for (const [dirRel, exportsParaAdicionar] of mapDestinos) {
        if (await criarBarrelSeNecessario(dirRel, exportsParaAdicionar, srcDir)) {
            barrisCriados++;
        }
    }
    const dirsDestino = new Set();
    for (const [, destino] of movimentos) {
        dirsDestino.add(path.posix.dirname(destino));
    }
    for (const dirRel of dirsDestino) {
        if (mapDestinos.has(dirRel))
            continue;
        const barrelPath = path.join(srcDir, dirRel, 'index.ts');
        if (existsSync(barrelPath))
            continue;
        const exportsNovos = [];
        for (const [, destino] of movimentos) {
            if (path.posix.dirname(destino) === dirRel) {
                const idxDest = [...movimentos.entries()].find(([, v]) => v === destino);
                if (idxDest) {
                    exportsNovos.push({ spec: '', resolved: idxDest[0], moveDest: destino });
                }
            }
        }
        if (exportsNovos.length > 0 && await criarBarrelSeNecessario(dirRel, exportsNovos, srcDir)) {
            barrisCriados++;
        }
    }
    const importsReescritos = await atualizarImportsGlobais(srcDir, movimentos);
    const importsReparados = await repararImportsBarrelPerdidos(srcDir, barrelsPerdidos, movimentos);
    const partes = [];
    if (barrisMovidos > 0)
        partes.push(`${barrisMovidos} movidos`);
    if (barrisModificados > 0)
        partes.push(`${barrisModificados} modificados`);
    if (barrisCriados > 0)
        partes.push(`${barrisCriados} criados`);
    if (barrisRemovidos > 0)
        partes.push(`${barrisRemovidos} removidos`);
    if (importsReescritos > 0)
        partes.push(`${importsReescritos} imports reescritos`);
    if (importsReparados > 0)
        partes.push(`${importsReparados} imports reparados`);
    if (partes.length > 0) {
        log.sucesso(`Barrels: ${partes.join(', ')}`);
    }
    else {
        log.info('Nenhum barrel ou import precisou de ajustes.');
    }
}
function listarArquivosDir(dir) {
    try {
        const entries = readdirSync(dir, { withFileTypes: true });
        const files = [];
        for (const entry of entries) {
            if (entry.isFile() && EXT_PATTERN.test(entry.name) && entry.name !== 'index.ts') {
                files.push(entry.name);
            }
        }
        return files.sort();
    }
    catch {
        return [];
    }
}
function exportsBarrelExistentes(content) {
    const exports = new Set();
    for (const linha of content.split('\n')) {
        const match = linha.trim().match(/^export\s+(?:\*\s+from|(?:type\s+)?\{[^}]*\}\s+from)\s+['"](.+)['"]\s*;/);
        if (match) {
            exports.add(match[1]);
        }
    }
    return exports;
}
function barrelEhPuroReexport(content) {
    for (const linha of content.split('\n')) {
        const trimmed = linha.trim();
        if (!trimmed)
            continue;
        if (trimmed.startsWith('//'))
            continue;
        if (trimmed.startsWith('/*'))
            continue;
        if (trimmed.startsWith('*'))
            continue;
        if (/^export\s+(?:\*\s+from|(?:type\s+)?\{[^}]*\}\s+from)\s+['"]/.test(trimmed))
            continue;
        return false;
    }
    return true;
}
export async function gerarBarrels(baseDir, dryRun = false) {
    const srcDir = path.join(baseDir, 'src');
    const resultado = {
        criados: 0,
        atualizados: 0,
        erros: [],
        barris: [],
    };
    if (!existsSync(srcDir)) {
        resultado.erros.push(`Diretório src não encontrado em ${baseDir}`);
        return resultado;
    }
    const dirs = [];
    try {
        const entries = await fsAsync.readdir(srcDir, { withFileTypes: true });
        const stack = entries
            .filter(e => e.isDirectory() && !SKIP_DIRS.has(e.name))
            .map(e => path.join(srcDir, e.name));
        while (stack.length > 0) {
            const dir = stack.pop();
            if (!dir)
                break;
            dirs.push(dir);
            try {
                const sub = await fsAsync.readdir(dir, { withFileTypes: true });
                for (const s of sub) {
                    if (s.isDirectory() && !SKIP_DIRS.has(s.name)) {
                        stack.push(path.join(dir, s.name));
                    }
                }
            }
            catch {
            }
        }
    }
    catch (err) {
        resultado.erros.push(`Erro ao varrer diretórios: ${err instanceof Error ? err.message : String(err)}`);
        return resultado;
    }
    for (const dir of dirs) {
        const files = listarArquivosDir(dir);
        if (files.length === 0)
            continue;
        const filesModulo = [];
        for (const f of files) {
            if (f.endsWith('.d.ts')) {
                try {
                    const content = await fsAsync.readFile(path.join(dir, f), 'utf-8');
                    if (!/^export\s/m.test(content))
                        continue;
                }
                catch {
                    continue;
                }
            }
            filesModulo.push(f);
        }
        if (filesModulo.length === 0)
            continue;
        const nomeExportParaArquivos = new Map();
        const exportacoesPorArquivo = new Map();
        for (const f of filesModulo) {
            try {
                const content = await fsAsync.readFile(path.join(dir, f), 'utf-8');
                const classified = classificarExports(content);
                exportacoesPorArquivo.set(f, classified);
                const todos = new Set([...classified.types, ...classified.values]);
                for (const nome of todos) {
                    const arr = nomeExportParaArquivos.get(nome);
                    if (arr)
                        arr.push(f);
                    else
                        nomeExportParaArquivos.set(nome, [f]);
                }
            }
            catch { }
        }
        async function gerarLinhasExportacao(filename) {
            const spec = `./${semExt(filename)}.js`;
            const classified = exportacoesPorArquivo.get(filename);
            if (!classified)
                return [`export * from '${spec}';`];
            const { types, values } = classified;
            const todos = new Set([...types, ...values]);
            const unicos = [];
            const conflitantes = [];
            for (const nome of todos) {
                const arquivos = nomeExportParaArquivos.get(nome);
                if (arquivos && arquivos.length > 1) {
                    const sorted = [...arquivos].sort();
                    if (sorted[0] === filename)
                        unicos.push(nome);
                    else
                        conflitantes.push(nome);
                }
                else {
                    unicos.push(nome);
                }
            }
            if (conflitantes.length === 0)
                return [`export * from '${spec}';`];
            if (unicos.length > 0) {
                const valuesUnicos = unicos.filter(n => values.has(n));
                const typesUnicos = unicos.filter(n => types.has(n));
                const parts = [];
                if (valuesUnicos.length > 0)
                    parts.push(valuesUnicos.join(', '));
                if (typesUnicos.length > 0)
                    parts.push(typesUnicos.map(n => `type ${n}`).join(', '));
                return [`export { ${parts.join(', ')} } from '${spec}';`];
            }
            return [];
        }
        const barrelPath = path.join(dir, 'index.ts');
        const dirRel = path.relative(srcDir, dir);
        if (existsSync(barrelPath)) {
            try {
                const content = await fsAsync.readFile(barrelPath, 'utf-8');
                if (!barrelEhPuroReexport(content)) {
                    resultado.barris.push({ caminho: dirRel, status: 'ok', detalhes: 'curado manualmente' });
                    continue;
                }
                const existentes = exportsBarrelExistentes(content);
                const linhasParaAdicionar = [];
                for (const f of filesModulo) {
                    const spec = `./${semExt(f)}.js`;
                    if (existentes.has(spec))
                        continue;
                    const novasLinhas = await gerarLinhasExportacao(f);
                    linhasParaAdicionar.push(...novasLinhas);
                }
                if (linhasParaAdicionar.length === 0) {
                    resultado.barris.push({ caminho: dirRel, status: 'ok' });
                    continue;
                }
                if (dryRun) {
                    resultado.barris.push({
                        caminho: dirRel,
                        status: 'atualizado',
                        detalhes: `Adicionaria ${linhasParaAdicionar.length} export(s)`,
                    });
                    resultado.atualizados++;
                    continue;
                }
                await fsAsync.writeFile(barrelPath, `${content.trimEnd()}\n${linhasParaAdicionar.join('\n')}\n`, 'utf-8');
                resultado.atualizados++;
                resultado.barris.push({
                    caminho: dirRel,
                    status: 'atualizado',
                    detalhes: `${linhasParaAdicionar.length} export(s) adicionado(s)`,
                });
            }
            catch (err) {
                const msg = err instanceof Error ? err.message : String(err);
                resultado.erros.push(`Erro ao atualizar barrel ${dirRel}: ${msg}`);
                resultado.barris.push({ caminho: dirRel, status: 'erro', detalhes: msg });
            }
        }
        else {
            if (dryRun) {
                resultado.barris.push({
                    caminho: dirRel,
                    status: 'criado',
                    detalhes: `Criaria barrel com ${filesModulo.length} export(s)`,
                });
                resultado.criados++;
                continue;
            }
            try {
                const linhas = [];
                for (const f of filesModulo) {
                    const l = await gerarLinhasExportacao(f);
                    linhas.push(...l);
                }
                await fsAsync.writeFile(barrelPath, `${linhas.join('\n')}\n`, 'utf-8');
                resultado.criados++;
                resultado.barris.push({
                    caminho: dirRel,
                    status: 'criado',
                    detalhes: `${linhas.length} export(s)`,
                });
            }
            catch (err) {
                const msg = err instanceof Error ? err.message : String(err);
                resultado.erros.push(`Erro ao criar barrel ${dirRel}: ${msg}`);
                resultado.barris.push({ caminho: dirRel, status: 'erro', detalhes: msg });
            }
        }
    }
    return resultado;
}
//# sourceMappingURL=reorganize-barrels.js.map