import { isInStringOrComment } from '../../shared/helpers/index.js';
export const LIMITES = {
    ASCII_EXTENDED_MIN: 128,
    CARACTERES_INCOMUNS_PADRAO: 10,
    ESPACAMENTO_CORRECAO_CONTAGEM: 1,
    CONTEXTO_TYPESCRIPT_LOOKBACK: 50,
    CONTEXTO_TYPESCRIPT_LOOKAHEAD: 50
};
export const INTERVALOS_UNICODE_COMUNS = [[0x0080, 0x00FF], [0x0100, 0x017F], [0x0180, 0x024F], [0x0250, 0x02AF], [0x02B0, 0x02FF], [0x0300, 0x036F], [0x0370, 0x03FF], [0x0400, 0x04FF], [0x2000, 0x206F], [0x2070, 0x209F], [0x20A0, 0x20CF], [0x2100, 0x214F], [0x2190, 0x21FF], [0x2200, 0x22FF], [0x2500, 0x257F], [0x2580, 0x259F], [0x25A0, 0x25FF], [0x2600, 0x26FF], [0x2700, 0x27BF], [0x3000, 0x30FF], [0x4E00, 0x9FFF], [0xAC00, 0xD7AF], [0xFE00, 0xFE0F], [0xFF00, 0xFFEF], [0x1F300, 0x1F5FF], [0x1F600, 0x1F64F], [0x1F680, 0x1F6FF], [0x1F700, 0x1F77F], [0x1F780, 0x1F7FF], [0x1F800, 0x1F8FF], [0x1F900, 0x1F9FF], [0x1FA00, 0x1FA6F], [0x1FA70, 0x1FAFF], [0xE0001, 0xE0001], [0xE0020, 0xE007F]];
export function isCaractereComum(code) {
    if (code >= 0xD800 && code <= 0xDFFF)
        return true;
    for (const [inicio, fim] of INTERVALOS_UNICODE_COMUNS) {
        if (code >= inicio && code <= fim)
            return true;
    }
    return false;
}
export const CONFIANCA = {
    MIN_ALTA: 80,
    UNICODE: 90,
    PONTUACAO: 95,
    ESPACAMENTO: 85,
    CARACTERES_INCOMUNS: 70
};
export const COMUM_SUBSTITUICOES = {
    '\u201c': '"',
    '\u201d': '"',
    '\u2018': "'",
    '\u2019': "'",
    '\u2013': '-',
    '\u2014': '-',
    '\u00A0': ' ',
    '\u00B4': "'"
};
export const REPEATABLE_TO_SINGLE = new Set([',', '.', '!', '?', ':', ';', '-', '_', '*']);
export const REPEATABLE_KEEP_UP_TO_3 = new Set(['.', '!', '?']);
export const MULTI_PUNCT_RE = /([,\.!?:;_\-\*]){2,}/g;
export const SPACE_BEFORE_PUNCT_RE = /\s+([,.:;!?])/g;
export const NO_SPACE_AFTER_NON_DOT_PUNCT_RE = /([,:;!?])([^\s\)\]\}!,;:?])/g;
export const SPACE_BEFORE_ELLIPSIS_RE = /([^0-9])(\.{3})/g;
const PROTECTED_PATTERNS = [/https?:\/\/[^\s"'<>]+/gi, /ftp:\/\/[^\s"'<>]+/gi, /file:\/\/[^\s"'<>]+/gi, /www\.[^\s"'<>]+/gi, /[a-zA-Z0-9](?:\.[a-zA-Z0-9-]+)+\.[a-zA-Z]{2,}/g, /(?:^|(?<=\s|["'=(\[,]))\.\//g, /(?:^|(?<=\s|["'=(\[,]))\.\.\//g, /(?<=[/\\])[\w-]+\.[\w]+/g, /\d+\.\d+(?:\.\d+)*/g, /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, /[a-f0-9]{7,}\.[a-f0-9]+/gi, /[\w-]+\.[\w-]+\.[\w]+/g, /[\w-]+\.[\w]+/g, /\.{3,}/g, /[-]{3,}/g, /[*]{2,}/g, /^---+$/gm, /^_{3,}$/gm, /\*\*[^*]+\*\*/g, /\*[^*]+\*/g, /__[^_]+__/g, /_[^_]+_/g, /\b\w+:\w+\b/g, /<!--[\s\S]*?-->/g, /\b[\w-]+:[\w./@-]+\b/g];
const _CODE_OPERATOR_PATTERNS = [/--/g, /\+\+/g, /\*\*/g, /::/g, /<=>/g, /<<=?/g, />>=?/g];
function protectSequences(code) {
    const placeholders = [];
    let result = code;
    for (const pattern of PROTECTED_PATTERNS) {
        pattern.lastIndex = 0;
        result = result.replace(pattern, match => {
            const id = placeholders.length;
            placeholders.push(match);
            return `\x00PROTECTED_${id}\x00`;
        });
    }
    return {
        text: result,
        placeholders
    };
}
function restoreSequences(code, placeholders) {
    return code.replace(/\x00PROTECTED_(\d+)\x00/g, (_m, id) => {
        return placeholders[Number(id)] ?? _m;
    });
}
export const NO_SPACE_AFTER_DOT_RE = /(?<![a-zA-Z0-9_.])\.(?![a-zA-Z0-9/\\])/g;
export const CONFIGURACAO_PADRAO = {
    normalizarUnicode: true,
    colapsarPontuacaoRepetida: true,
    corrigirEspacamento: true,
    balancearParenteses: false,
    detectarCaracteresIncomuns: true,
    limiteCaracteresIncomuns: LIMITES.CARACTERES_INCOMUNS_PADRAO
};
export function normalizeUnicode(input) {
    let normalized = input.normalize('NFKC');
    let changed = false;
    for (const [pattern, replacement] of Object.entries(COMUM_SUBSTITUICOES)) {
        if (normalized.includes(pattern)) {
            normalized = normalized.split(pattern).join(replacement);
            changed = true;
        }
    }
    return {
        text: normalized,
        changed
    };
}
export function isTypeScriptContext(src, index) {
    const before = src.substring(Math.max(0, index - LIMITES.CONTEXTO_TYPESCRIPT_LOOKBACK), index);
    const after = src.substring(index, Math.min(src.length, index + LIMITES.CONTEXTO_TYPESCRIPT_LOOKAHEAD));
    const tsPadroes = [/\?\s*:\s*$/,
        /:\s*\?/,
        /\(\?\s*:\s*$/,
        /interface\s+\w+\s*{/,
        /type\s+\w+\s*=/,
        /<[^>]*$/
    ];
    return tsPadroes.some(pattern => pattern.test(before) || pattern.test(after));
}
function isMarkdownOrCodePattern(text, index, matchStr) {
    const before = text.substring(0, index);
    const _after = text.substring(index + matchStr.length);
    const lineStart = before.lastIndexOf('\n') + 1;
    const lineEnd = text.indexOf('\n', index + matchStr.length);
    const line = text.substring(lineStart, lineEnd === -1 ? undefined : lineEnd);
    const posInLine = index - lineStart;
    if (/^-{3,}$/.test(line.trim()) || /^\*{3,}$/.test(line.trim()) || /^_{3,}$/.test(line.trim())) {
        return true;
    }
    if (/^{-{3,}}/.test(line.trim()) || /^\*{3,}\*/.test(line.trim())) {
        return true;
    }
    if (/^>\s?/.test(line) && posInLine === 0) {
        return true;
    }
    if (/^[-*]\s/.test(line) && posInLine === 0) {
        return true;
    }
    if (/^\d+\.\s/.test(line) && posInLine === 0) {
        return true;
    }
    const beforeInLine = line.substring(0, posInLine);
    const afterInLine = line.substring(posInLine + matchStr.length);
    if (matchStr[0] === '*') {
        const openStars = (beforeInLine.match(/\*/g) || []).length;
        const closeStars = (afterInLine.match(/\*/g) || []).length;
        if (openStars % 2 === 1 && closeStars >= 1)
            return true;
        if (/\*\*[^*]*$/.test(beforeInLine) && /^[^*]*\*\*/.test(afterInLine))
            return true;
    }
    if (matchStr[0] === '_') {
        const openUnders = (beforeInLine.match(/_/g) || []).length;
        const closeUnders = (afterInLine.match(/_/g) || []).length;
        if (openUnders % 2 === 1 && closeUnders >= 1)
            return true;
    }
    if (matchStr[0] === '-' && /^-{3,}$/.test(matchStr))
        return true;
    if (matchStr === '--' || matchStr === '::' || matchStr === '**') {
        return true;
    }
    if (/^\|.*\|$/.test(line.trim())) {
        return true;
    }
    if (matchStr === ':' && /^[\w-]+:[\w./@-]+/.test(afterInLine.trimStart())) {
        return true;
    }
    if (matchStr === '--' && /^-\w/.test(afterInLine)) {
        return true;
    }
    return false;
}
export function collapseRepeatedPunct(string) {
    let count = 0;
    const { text: protectedStr, placeholders } = protectSequences(string);
    let result = protectedStr;
    MULTI_PUNCT_RE.lastIndex = 0;
    let match;
    while ((match = MULTI_PUNCT_RE.exec(result)) !== null) {
        const matchIndex = match.index;
        const matchStr = match[0];
        const ch = matchStr[0];
        if (isInStringOrComment(result, matchIndex) || ch === ':' && isTypeScriptContext(result, matchIndex)) {
            continue;
        }
        if (isMarkdownOrCodePattern(result, matchIndex, matchStr)) {
            continue;
        }
        let replacement;
        if (REPEATABLE_KEEP_UP_TO_3.has(ch)) {
            replacement = ch.repeat(Math.min(matchStr.length, 3));
        }
        else if (REPEATABLE_TO_SINGLE.has(ch)) {
            replacement = ch;
        }
        else {
            replacement = matchStr;
        }
        if (replacement !== matchStr) {
            result = result.slice(0, matchIndex) + replacement + result.slice(matchIndex + matchStr.length);
            count++;
            MULTI_PUNCT_RE.lastIndex = matchIndex + replacement.length;
        }
    }
    return {
        text: restoreSequences(result, placeholders),
        changed: count > 0,
        count
    };
}
export function fixSpacingAroundPunct(string) {
    const { text: protected_s, placeholders } = protectSequences(string);
    const t1 = protected_s.replace(SPACE_BEFORE_PUNCT_RE, '$1');
    const t2 = t1.replace(NO_SPACE_AFTER_NON_DOT_PUNCT_RE, '$1 $2');
    const t3 = t2.replace(NO_SPACE_AFTER_DOT_RE, '. ');
    const t4 = t3.replace(SPACE_BEFORE_ELLIPSIS_RE, '$1 $2');
    const restored = restoreSequences(t4, placeholders);
    const changed = string !== restored;
    const count = changed ? LIMITES.ESPACAMENTO_CORRECAO_CONTAGEM : 0;
    return {
        text: restored,
        changed,
        count
    };
}
export function detectUncommonChars(text, limite) {
    const issues = [];
    let pos = 0;
    for (const ch of text) {
        if (issues.length >= (limite ?? Infinity))
            break;
        const code = ch.codePointAt(0) ?? 0;
        if (code >= LIMITES.ASCII_EXTENDED_MIN && !isCaractereComum(code)) {
            const name = (() => {
                try {
                    if (typeof Intl !== 'undefined') {
                        const intlApi = Intl;
                        const DisplayNomesCtor = intlApi.DisplayNames;
                        if (DisplayNomesCtor) {
                            const displayNomes = new DisplayNomesCtor(['en'], {
                                type: 'language'
                            });
                            return typeof displayNomes.of === 'function' ? displayNomes.of(ch) ?? '' : '';
                        }
                    }
                    return '';
                }
                catch {
                    return '';
                }
            })();
            issues.push({
                tipo: 'caracteres-incomuns',
                posicao: pos,
                comprimento: ch.length,
                descricao: `Caractere incomum: ${ch} (${name || ch})`,
                sugestao: 'Considere substituir por equivalente ASCII',
                confianca: CONFIANCA.CARACTERES_INCOMUNS
            });
        }
        pos += ch.length;
    }
    return issues;
}
export function analisarTexto(src, config = CONFIGURACAO_PADRAO) {
    const problemas = [];
    const isMarkdown = src.includes('# ') || src.includes('## ') || /^---$/.test(src.trim().split('\n')[0] || '');
    if (config.normalizarUnicode && !isMarkdown) {
        const norm = normalizeUnicode(src);
        if (norm.changed) {
            problemas.push({
                tipo: 'unicode-invalido',
                posicao: 0,
                comprimento: src.length,
                descricao: 'Texto contém caracteres Unicode que podem ser normalizados',
                sugestao: 'Aplicar normalização Unicode NFKC',
                confianca: CONFIANCA.UNICODE
            });
        }
    }
    if (config.colapsarPontuacaoRepetida && !isMarkdown) {
        const collapsed = collapseRepeatedPunct(src);
        if (collapsed.changed) {
            problemas.push({
                tipo: 'pontuacao-repetida',
                posicao: 0,
                comprimento: src.length,
                descricao: `Encontrados ${collapsed.count} casos de pontuação repetida`,
                sugestao: 'Colapsar pontuação repetida para caracteres únicos',
                confianca: CONFIANCA.PONTUACAO
            });
        }
    }
    if (config.corrigirEspacamento && !isMarkdown) {
        const spacing = fixSpacingAroundPunct(src);
        if (spacing.changed) {
            problemas.push({
                tipo: 'espacamento-incorreto',
                posicao: 0,
                comprimento: src.length,
                descricao: `Encontrados ${spacing.count} problemas de espaçamento em pontuação`,
                sugestao: 'Corrigir espaçamento antes/depois de pontuação',
                confianca: CONFIANCA.ESPACAMENTO
            });
        }
    }
    if (config.detectarCaracteresIncomuns && !isMarkdown) {
        const uncommon = detectUncommonChars(src, config.limiteCaracteresIncomuns ?? undefined);
        problemas.push(...uncommon);
    }
    return problemas;
}
export function calcularLinha(src, posOrIndex, match) {
    if (typeof posOrIndex === 'number') {
        return src.substring(0, posOrIndex).split('\n').length;
    }
    if (match) {
        const idx = match.index;
        if (typeof idx === 'number') {
            return src.substring(0, idx).split('\n').length;
        }
    }
    return 1;
}
//# sourceMappingURL=scoring-shared.js.map