import XXH from 'xxhashjs';
function toRecord(valor) {
    if (typeof valor === 'object' && valor !== null && !Array.isArray(valor)) {
        return valor;
    }
    return undefined;
}
function isNodePath(ast) {
    return typeof ast === 'object' && ast !== null && 'node' in ast;
}
const RE_FUNCAO = /^\s*(?:export\s+)?(?:async\s+)?function\s+\*?\s*(\w+)\s*\(/gm;
const RE_CLASSE = /^\s*(?:export\s+)?class\s+(\w+)/gm;
const RE_IMPORT = /^\s*import\s+(?:\{[^}]*\}\s*|[\w*]\s*,?\s*)?from\s+['"]([^'"]+)['"]/gm;
const RE_EXPORT_FUNCAO = /^\s*export\s+(?:async\s+)?function\s+\*?\s*(\w+)/gm;
const RE_EXPORT_CLASSE = /^\s*export\s+class\s+(\w+)/gm;
const RE_EXPORT_VAR = /^\s*export\s+(?:const|let|var)\s+(\w+)/gm;
const RE_EXPORT_DEFAULT = /^\s*export\s+default\s+(?:function|class)\s+(\w+)/gm;
const RE_INTERFACE = /^\s*(?:export\s+)?interface\s+(\w+)/gm;
const RE_TYPE = /^\s*(?:export\s+)?type\s+(\w+)\s*=/gm;
const RE_ENUM = /^\s*(?:export\s+)?enum\s+(\w+)/gm;
function extrairEstrutura(ast) {
    const elementos = [];
    if (!ast || typeof ast !== 'object')
        return elementos;
    const node = isNodePath(ast) ? ast.node : ast;
    if (!node || typeof node !== 'object')
        return elementos;
    const nodeRecord = toRecord(node);
    if (!nodeRecord || nodeRecord.type !== 'File' || !nodeRecord.program)
        return elementos;
    const program = toRecord(nodeRecord.program);
    if (!program)
        return elementos;
    const body = Array.isArray(program.body) ? program.body : [];
    for (const stmt of body) {
        const tipo = String(stmt.type || '');
        const stmtRecord = toRecord(stmt);
        if (!stmtRecord)
            continue;
        switch (tipo) {
            case 'ImportDeclaration': {
                const sourceRec = toRecord(stmtRecord.source);
                if (sourceRec && typeof sourceRec.value === 'string') {
                    elementos.push(`import:${sourceRec.value}`);
                }
                break;
            }
            case 'ExportNamedDeclaration':
            case 'ExportDefaultDeclaration': {
                const decl = toRecord(stmtRecord.declaration);
                if (decl && decl.type === 'FunctionDeclaration') {
                    const idObj = toRecord(decl.id);
                    if (idObj && typeof idObj.name === 'string') {
                        elementos.push(`export:function:${idObj.name}`);
                    }
                    else {
                        elementos.push('export:function:anonymous');
                    }
                }
                else if (decl && decl.type === 'ClassDeclaration') {
                    const idObj = toRecord(decl.id);
                    if (idObj && typeof idObj.name === 'string') {
                        elementos.push(`export:class:${idObj.name}`);
                    }
                }
                else if (decl && decl.type === 'VariableDeclaration') {
                    const vars = extractVariableNames(decl);
                    for (const v of vars)
                        elementos.push(`export:var:${v}`);
                }
                else if (stmtRecord.type === 'ExportDefaultDeclaration') {
                    elementos.push('export:default');
                }
                else {
                    elementos.push('export:named');
                }
                break;
            }
            case 'FunctionDeclaration': {
                const idObj = toRecord(stmtRecord.id);
                if (idObj && typeof idObj.name === 'string') {
                    elementos.push(`function:${idObj.name}`);
                }
                break;
            }
            case 'ClassDeclaration': {
                const idObj = toRecord(stmtRecord.id);
                if (idObj && typeof idObj.name === 'string') {
                    elementos.push(`class:${idObj.name}`);
                }
                break;
            }
            case 'VariableDeclaration': {
                const vars = extractVariableNames(stmtRecord);
                for (const v of vars)
                    elementos.push(`var:${v}`);
                break;
            }
            case 'TSTypeAliasDeclaration':
            case 'TypeAlias': {
                const idObj = toRecord(stmtRecord.id);
                if (idObj && typeof idObj.name === 'string') {
                    elementos.push(`type:${idObj.name}`);
                }
                break;
            }
            case 'TSInterfaceDeclaration':
            case 'InterfaceDeclaration': {
                const idObj = toRecord(stmtRecord.id);
                if (idObj && typeof idObj.name === 'string') {
                    elementos.push(`interface:${idObj.name}`);
                }
                break;
            }
            case 'TSEnumDeclaration':
            case 'EnumDeclaration': {
                const idObj = toRecord(stmtRecord.id);
                if (idObj && typeof idObj.name === 'string') {
                    elementos.push(`enum:${idObj.name}`);
                }
                break;
            }
            case 'ExportAllDeclaration': {
                const sourceRec = toRecord(stmtRecord.source);
                if (sourceRec && typeof sourceRec.value === 'string') {
                    elementos.push(`export-all:${sourceRec.value}`);
                }
                break;
            }
        }
    }
    return elementos.sort();
}
function extractVariableNames(decl) {
    const names = [];
    const declarations = Array.isArray(decl.declarations) ? decl.declarations : [];
    for (const d of declarations) {
        const idObj = toRecord(d);
        if (idObj && typeof idObj.name === 'string') {
            names.push(idObj.name);
        }
    }
    return names;
}
function extrairEstruturaDoConteudo(content) {
    const elementos = [];
    const seen = new Set();
    function add(el) {
        if (!seen.has(el)) {
            seen.add(el);
            elementos.push(el);
        }
    }
    let match;
    while ((match = RE_FUNCAO.exec(content)) !== null)
        add(`function:${match[1]}`);
    while ((match = RE_CLASSE.exec(content)) !== null)
        add(`class:${match[1]}`);
    while ((match = RE_IMPORT.exec(content)) !== null)
        add(`import:${match[1]}`);
    while ((match = RE_EXPORT_FUNCAO.exec(content)) !== null)
        add(`export:function:${match[1]}`);
    while ((match = RE_EXPORT_CLASSE.exec(content)) !== null)
        add(`export:class:${match[1]}`);
    while ((match = RE_EXPORT_VAR.exec(content)) !== null)
        add(`export:var:${match[1]}`);
    while ((match = RE_EXPORT_DEFAULT.exec(content)) !== null)
        add(`export:default:${match[1]}`);
    while ((match = RE_INTERFACE.exec(content)) !== null)
        add(`interface:${match[1]}`);
    while ((match = RE_TYPE.exec(content)) !== null)
        add(`type:${match[1]}`);
    while ((match = RE_ENUM.exec(content)) !== null)
        add(`enum:${match[1]}`);
    return elementos.sort();
}
function hashString(str) {
    try {
        return XXH.h64(str, 0xdef).toString(16);
    }
    catch {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            hash = ((hash << 5) - hash) + str.charCodeAt(i);
            hash |= 0;
        }
        return (hash >>> 0).toString(16);
    }
}
export function calcularHashEstrutural(ast, content) {
    let estrutura;
    if (ast && typeof ast === 'object') {
        estrutura = extrairEstrutura(ast);
    }
    else {
        estrutura = [];
    }
    if (estrutura.length === 0 && content) {
        estrutura = extrairEstruturaDoConteudo(content);
    }
    if (estrutura.length === 0)
        return '';
    return hashString(estrutura.join('|'));
}
//# sourceMappingURL=structural-hash.js.map