'use strict'; const { getDb } = require('../db/database'); // Lazy-loaded in-memory cache — loaded once on first use let _patterns = null; let _overrideTerms = null; function normalize(text) { if (!text) return ''; return String(text) .toLowerCase() .replace(/&/g, 'and') .replace(/\s+/g, ' ') .trim(); } function loadCache() { if (_patterns !== null) return; const db = getDb(); _patterns = db.prepare( 'SELECT pattern, confidence, category, rationale FROM advisory_non_bill_filters' ).all(); _overrideTerms = db.prepare( 'SELECT term FROM advisory_bill_like_overrides' ).all().map(r => r.term); } /** * Check a transaction title against advisory filter patterns. * Returns null if Create Bill should be shown normally, or * { confidence: 'high'|'medium', category, rationale } if it should be suppressed. */ function checkTransaction(title) { if (!title) return null; try { loadCache(); } catch { return null; } const normalized = normalize(title); if (!normalized) return null; // Bill-like override terms take priority — always show Create Bill for (const term of _overrideTerms) { if (normalized.includes(term)) return null; } // Find the highest-confidence matching pattern let highMatch = null; let mediumMatch = null; for (const row of _patterns) { if (normalized.includes(row.pattern)) { if (row.confidence === 'high') { highMatch = row; break; // high confidence — no need to keep looking } else if (!mediumMatch) { mediumMatch = row; } } } const match = highMatch || mediumMatch; if (!match) return null; return { confidence: match.confidence, category: match.category, rationale: match.rationale || null, }; } /** Clear the in-memory cache (used after re-seeding in tests). */ function clearCache() { _patterns = null; _overrideTerms = null; } module.exports = { checkTransaction, clearCache };