import { createRequire } from 'node:module';
import { corrigirPontuacaoECodigoConservador, limitarLinhasEmBranco, normalizarFimDeLinha, normalizarNewlinesFinais, normalizarUnicode, removerBom, removerEspacosFinaisPorLinhaComProtecao } from './commons.js';
const SPECIAL_TITLES_BY_SYMBOL = {
    FormatadorMensagens: 'MENSAGENS FORMATADOR (MIN)',
    SvgMensagens: 'MENSAGENS SVG (OTIMIZAÇÃO)'
};
export function isJsTsFile(relPath) {
    const rp = (relPath ?? '').toLowerCase();
    return rp.endsWith('.ts') || rp.endsWith('.tsx') || rp.endsWith('.cts') || rp.endsWith('.mts') || rp.endsWith('.js') || rp.endsWith('.jsx') || rp.endsWith('.mjs') || rp.endsWith('.cjs');
}
function isAstNode(value) {
    return typeof value === 'object' && value !== null;
}
export function getProtectedLinesFromTemplateLiterals(code, relPath) {
    try {
        const req = createRequire(import.meta.url);
        const parser = req('@babel/parser');
        const rp = (relPath ?? '').toLowerCase();
        const plugins = ['importMeta', 'dynamicImport', 'topLevelAwait', 'classProperties', 'classPrivateProperties', 'classPrivateMethods', 'classStaticBlock', 'optionalChaining', 'nullishCoalescingOperator', 'numericSeparator', 'logicalAssignment', 'privateIn', 'objectRestSpread', 'decorators-legacy'];
        const isTs = rp.endsWith('.ts') || rp.endsWith('.tsx') || rp.endsWith('.cts') || rp.endsWith('.mts');
        const isJsx = rp.endsWith('.jsx') || rp.endsWith('.tsx');
        if (isTs)
            plugins.push('typescript');
        if (isJsx)
            plugins.push('jsx');
        const ast = parser.parse(code, {
            sourceType: 'unambiguous',
            errorRecovery: true,
            allowReturnOutsideFunction: true,
            allowAwaitOutsideFunction: true,
            plugins
        });
        const protectedLines = new Set();
        const seen = new Set();
        const walk = (node) => {
            if (!isAstNode(node))
                return;
            if (seen.has(node))
                return;
            seen.add(node);
            if (node.type === 'TemplateLiteral') {
                const loc = node.loc;
                if (loc && typeof loc === 'object' && 'start' in loc && 'end' in loc) {
                    const start = loc.start;
                    const end = loc.end;
                    const startLine = typeof start.line === 'number' ? start.line : 0;
                    const endLine = typeof end.line === 'number' ? end.line : 0;
                    if (startLine > 0 && endLine > 0) {
                        for (let ln = startLine; ln <= endLine; ln++)
                            protectedLines.add(ln);
                    }
                }
            }
            for (const chave of Object.keys(node)) {
                if (chave === 'loc' || chave === 'start' || chave === 'end')
                    continue;
                const valor = node[chave];
                if (Array.isArray(valor)) {
                    for (const item of valor)
                        walk(item);
                    continue;
                }
                if (isAstNode(valor) && typeof valor.type === 'string')
                    walk(valor);
            }
        };
        walk(ast);
        return protectedLines.size > 0 ? protectedLines : null;
    }
    catch {
        return null;
    }
}
export function normalizarSeparadoresDeSecao(code, opts = {}) {
    const lines = normalizarFimDeLinha(code).split('\n');
    const out = [];
    let changed = false;
    const toUpperTitle = (raw) => {
        const trimmed = raw.trim();
        if (!trimmed)
            return trimmed;
        const withSpaces = trimmed.replace(/([a-z\d])([A-Z])/g, '$1 $2').replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2').replace(/[_\-]+/g, ' ').replace(/\s+/g, ' ').trim();
        return withSpaces.toUpperCase();
    };
    const inferTitleFromNextSymbol = (fromIndex) => {
        for (let indice = fromIndex + 1; indice < Math.min(lines.length, fromIndex + 35); indice++) {
            const linha = (lines[indice] ?? '').trim();
            if (!linha)
                continue;
            if (linha.startsWith('//'))
                continue;
            if (linha.startsWith('/*'))
                continue;
            if (linha.startsWith('#'))
                continue;
            const metrica = linha.match(/^(?:export\s+)?(?:const|function|class|interface|type)\s+([A-Za-z_$][\w$]*)\b/);
            if (!metrica)
                continue;
            const symbol = metrica[1] ?? '';
            if (!symbol)
                continue;
            const special = SPECIAL_TITLES_BY_SYMBOL[symbol];
            if (special)
                return special;
            if (symbol.endsWith('Messages')) {
                const base = symbol.slice(0, -'Messages'.length);
                const baseTitle = toUpperTitle(base);
                return baseTitle ? `MENSAGENS ${baseTitle}` : 'MENSAGENS';
            }
            return toUpperTitle(symbol);
        }
        const relPath = (opts.relPath ?? '').toLowerCase();
        if (relPath.includes('/messages/') || relPath.includes('messages'))
            return 'MENSAGENS';
        return null;
    };
    const parseNovoSeparadorComMarcacao = (line) => {
        const metrica = line.match(/^\s*\/\*\s*-{10,}\s*substituir\s+por\s+titulo\s+@tutanus-secao(?:\((.+?)\))?\s*-{10,}\s*\*\/\s*$/i);
        if (!metrica)
            return null;
        const raw = (metrica[1] ?? '').trim();
        return {
            titulo: raw ? raw : null
        };
    };
    const isSeparadorSemTitulo = (line) => {
        return /^\s*\/\*\s*-{10,}\s*substituir\s+por\s+titulo\s*-{10,}\s*\*\/\s*$/i.test(line) || /^\s*\/\*\s*-{10,}\s*-\s*-{10,}\s*\*\/\s*$/.test(line) || /^\s*\/\*\s*-{10,}\s*@tutanus-secao\s*-{10,}\s*\*\/\s*$/i.test(line);
    };
    const LINE_WIDTH = 65;
    const buildSeparatorWithTitle = (title) => {
        const prefix = '// ─── ';
        const dashesLen = Math.max(3, LINE_WIDTH - prefix.length - title.length - 1);
        return `${prefix}${title} ${'─'.repeat(dashesLen)}`;
    };
    const isDivider = (line) => {
        return /^\s*\/\/\s*(?:[=\-_*]){8,}\s*$/.test(line)
            || /^\s*\/\*\s*(?:[=\-_*]){8,}\s*\*\/\s*$/.test(line)
            || /^\s*#\s*(?:[=\-_*]){8,}\s*$/.test(line)
            || /^\s*(?:[=\-_*]){8,}\s*$/.test(line);
    };
    const extractTitleFromLineComment = (line) => {
        const metrica = line.match(/^\s*\/\/\s*(.+?)\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        if (!textoTitulo)
            return null;
        if (/^(?:[=\-_*]){5,}$/.test(textoTitulo))
            return null;
        return textoTitulo;
    };
    const extractTitleFromBlockComment = (line) => {
        const metrica = line.match(/^\s*\/\*\s*(.+?)\s*\*\/\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        if (!textoTitulo)
            return null;
        if (/^(?:[=\-_*]){5,}$/.test(textoTitulo))
            return null;
        return textoTitulo;
    };
    const extractTitleFromHashComment = (line) => {
        const metrica = line.match(/^\s*#\s*(.+?)\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        if (!textoTitulo)
            return null;
        if (/^(?:[=\-_*]){5,}$/.test(textoTitulo))
            return null;
        return textoTitulo;
    };
    const extractTitleFromSingleLine = (line) => {
        const metrica = line.match(/^\s*\/\/\s*(?:[=\-_*]){5,}\s*(.+?)\s*(?:[=\-_*]){5,}\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        return textoTitulo ? textoTitulo : null;
    };
    const extractTitleFromSingleBlockLine = (line) => {
        const metrica = line.match(/^\s*\/\*\s*(?:[=\-_*]){5,}\s*(.+?)\s*(?:[=\-_*]){5,}\s*\*\/\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        return textoTitulo ? textoTitulo : null;
    };
    const extractTitleFromSingleHashLine = (line) => {
        const metrica = line.match(/^\s*#\s*(?:[=\-_*]){5,}\s*(.+?)\s*(?:[=\-_*]){5,}\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        return textoTitulo ? textoTitulo : null;
    };
    const extractTitleFromSingleBareLine = (line) => {
        const metrica = line.match(/^\s*(?:[=\-_*]){5,}\s*(.+?)\s*(?:[=\-_*]){5,}\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        if (!textoTitulo)
            return null;
        if (/^(?:[=\-_*]){5,}$/.test(textoTitulo))
            return null;
        return textoTitulo;
    };
    const extractTitleFromOldBlockFormat = (line) => {
        const metrica = line.match(/^\s*\/\*\s*-{3}\s+(.+?)\s+-{3}\s*\*\/\s*$/);
        if (!metrica)
            return null;
        const textoTitulo = metrica[1].trim();
        return textoTitulo || null;
    };
    for (let indice = 0; indice < lines.length; indice++) {
        const line = lines[indice] ?? '';
        const lineNo = indice + 1;
        if (opts.protectedLines && opts.protectedLines.has(lineNo)) {
            out.push(line);
            continue;
        }
        if (isSeparadorSemTitulo(line)) {
            const inferred = inferTitleFromNextSymbol(indice);
            if (inferred) {
                out.push(buildSeparatorWithTitle(inferred));
                changed = true;
            }
            else {
                out.push(line);
            }
            continue;
        }
        const novo = parseNovoSeparadorComMarcacao(line);
        if (novo) {
            if (novo.titulo) {
                out.push(buildSeparatorWithTitle(novo.titulo));
                changed = true;
            }
            else {
                const inferred = inferTitleFromNextSymbol(indice);
                if (inferred) {
                    out.push(buildSeparatorWithTitle(inferred));
                    changed = true;
                }
                else {
                    out.push(line);
                }
            }
            continue;
        }
        if (isDivider(line) && indice + 2 < lines.length && isDivider(lines[indice + 2] ?? '')) {
            if (opts.protectedLines && (opts.protectedLines.has(indice + 1) || opts.protectedLines.has(indice + 2) || opts.protectedLines.has(indice + 3))) {
                out.push(line);
                continue;
            }
            const middle = lines[indice + 1] ?? '';
            const title = extractTitleFromLineComment(middle) ?? extractTitleFromBlockComment(middle) ?? extractTitleFromHashComment(middle);
            if (title) {
                out.push(buildSeparatorWithTitle(title));
                indice += 2;
                changed = true;
                continue;
            }
        }
        const singleLine = extractTitleFromSingleLine(line);
        const singleBlock = extractTitleFromSingleBlockLine(line);
        const singleHash = extractTitleFromSingleHashLine(line);
        const singleBare = extractTitleFromSingleBareLine(line);
        const singleOldBlock = extractTitleFromOldBlockFormat(line);
        const single = singleLine ?? singleBlock ?? singleHash ?? singleBare ?? singleOldBlock;
        if (single) {
            out.push(buildSeparatorWithTitle(single));
            changed = true;
            continue;
        }
        out.push(line);
    }
    return {
        code: out.join('\n'),
        changed
    };
}
export function formatarCodeMinimo(code, opts = {}) {
    const semBom = removerBom(code);
    const { text: comUnicode, changed: changedUnicode } = normalizarUnicode(semBom);
    const normalized = normalizarFimDeLinha(comUnicode);
    const protectedLines = opts.relPath && isJsTsFile(opts.relPath) ? getProtectedLinesFromTemplateLiterals(normalized, opts.relPath) : null;
    const semEspacosFinais = removerEspacosFinaisPorLinhaComProtecao(normalized, protectedLines);
    const { text: comPontuacao, stats } = corrigirPontuacaoECodigoConservador(semEspacosFinais);
    const shouldNormalizeSeparators = opts.normalizarSeparadoresDeSecao ?? true;
    const { code: maybeSeparadores, changed: changedSeparators } = shouldNormalizeSeparators ? normalizarSeparadoresDeSecao(comPontuacao, {
        relPath: opts.relPath,
        protectedLines
    }) : {
        code: comPontuacao,
        changed: false
    };
    const { code: semBlanks, changed: changedBlanks } = limitarLinhasEmBranco(maybeSeparadores, 2, protectedLines);
    const formatted = normalizarNewlinesFinais(semBlanks);
    const baseline = normalizarNewlinesFinais(normalized);
    const changed = formatted !== baseline;
    const reasons = [];
    if (changedUnicode)
        reasons.push('unicode');
    if (stats.pontuacaoRepetida > 0)
        reasons.push(`punct:${stats.pontuacaoRepetida}`);
    if (stats.espacamentoIncorreto > 0)
        reasons.push(`space:${stats.espacamentoIncorreto}`);
    if (changedSeparators)
        reasons.push('separadores');
    if (changedBlanks)
        reasons.push('blanks');
    return {
        ok: true,
        parser: opts.parser ?? 'code',
        formatted,
        changed,
        reason: reasons.length > 0 ? `estilo-tutanus(${reasons.join(',')})` : 'normalizacao-basica'
    };
}
export function formatarTypeScriptMinimo(code, relPath) {
    const semBom = removerBom(code);
    const { text: comUnicode, changed: changedUnicode } = normalizarUnicode(semBom);
    const normalized = normalizarFimDeLinha(comUnicode);
    const protectedLines = getProtectedLinesFromTemplateLiterals(normalized, relPath);
    const semEspacos = removerEspacosFinaisPorLinhaComProtecao(normalized, protectedLines);
    const { text: comPontuacao, stats } = corrigirPontuacaoECodigoConservador(semEspacos);
    const { code: comSeparadores } = normalizarSeparadoresDeSecao(comPontuacao, {
        relPath,
        protectedLines
    });
    const { code: limitado } = limitarLinhasEmBranco(comSeparadores, 2, protectedLines);
    const formatted = normalizarNewlinesFinais(limitado);
    const baseline = normalizarNewlinesFinais(normalized);
    const reasons = [];
    if (changedUnicode)
        reasons.push('unicode');
    if (stats.pontuacaoRepetida > 0)
        reasons.push(`punct:${stats.pontuacaoRepetida}`);
    if (stats.espacamentoIncorreto > 0)
        reasons.push(`space:${stats.espacamentoIncorreto}`);
    return {
        ok: true,
        parser: 'typescript',
        formatted,
        changed: formatted !== baseline,
        reason: reasons.length > 0 ? `estilo-tutanus-typescript(${reasons.join(',')})` : 'estilo-tutanus-typescript'
    };
}
export function formatarJavaScriptMinimo(code, relPath) {
    const semBom = removerBom(code);
    const { text: comUnicode, changed: changedUnicode } = normalizarUnicode(semBom);
    const normalized = normalizarFimDeLinha(comUnicode);
    const protectedLines = getProtectedLinesFromTemplateLiterals(normalized, relPath);
    const semEspacos = removerEspacosFinaisPorLinhaComProtecao(normalized, protectedLines);
    const { text: comPontuacao, stats } = corrigirPontuacaoECodigoConservador(semEspacos);
    const { code: comSeparadores } = normalizarSeparadoresDeSecao(comPontuacao, {
        relPath,
        protectedLines
    });
    const { code: limitado } = limitarLinhasEmBranco(comSeparadores, 2, protectedLines);
    const formatted = normalizarNewlinesFinais(limitado);
    const baseline = normalizarNewlinesFinais(normalized);
    const reasons = [];
    if (changedUnicode)
        reasons.push('unicode');
    if (stats.pontuacaoRepetida > 0)
        reasons.push(`punct:${stats.pontuacaoRepetida}`);
    if (stats.espacamentoIncorreto > 0)
        reasons.push(`space:${stats.espacamentoIncorreto}`);
    return {
        ok: true,
        parser: 'babel',
        formatted,
        changed: formatted !== baseline,
        reason: reasons.length > 0 ? `estilo-tutanus-javascript(${reasons.join(',')})` : 'estilo-tutanus-javascript'
    };
}
export function formatarPythonMinimo(code) {
    const semBom = removerBom(code);
    const { text: comUnicode, changed: changedUnicode } = normalizarUnicode(semBom);
    const normalized = normalizarFimDeLinha(comUnicode);
    const lines = normalized.split('\n');
    const out = [];
    for (const raw of lines) {
        out.push(raw.replace(/[ \t]+$/, ''));
    }
    const { code: limitado } = limitarLinhasEmBranco(out.join('\n'), 2);
    const formatted = normalizarNewlinesFinais(limitado);
    const baseline = normalizarNewlinesFinais(normalized);
    return {
        ok: true,
        parser: 'python',
        formatted,
        changed: formatted !== baseline,
        reason: changedUnicode ? 'estilo-tutanus-python(unicode)' : 'estilo-tutanus-python'
    };
}
export function formatarPhpMinimo(code) {
    return formatarCodeMinimo(code, {
        normalizarSeparadoresDeSecao: false,
        parser: 'php'
    });
}
//# sourceMappingURL=code.js.map