/**
 * SQL Table Extractor
 *
 * Extract candidate table names from SQL string using regex on FROM/JOIN clauses.
 * Returns lowercase, schema-stripped names. Comments dan literal string di-strip
 * sebelum scan untuk mengurangi false positive.
 *
 * Pattern yang ditangkap:
 *   - FROM table_name
 *   - FROM schema.table_name
 *   - JOIN table_name (semua varian: INNER/LEFT/RIGHT/FULL/CROSS)
 *   - WITH cte_name AS (...) — terdeteksi tapi caller bertanggung jawab
 *     filter via cross-reference metadata
 *
 * Tidak menangani:
 *   - Function-as-table seperti unnest(...) atau LATERAL
 *   - Subquery alias (akan tertangkap sebagai candidate, di-filter caller)
 *
 * @module lib/utils/sql-table-extractor
 */

// Strip single-line dan multi-line SQL comments + literal strings agar regex
// tidak match di dalam komentar atau string literal.
function stripCommentsAndStrings(sql) {
    return sql
        .replace(/--[^\n]*/g, ' ')
        .replace(/\/\*[\s\S]*?\*\//g, ' ')
        .replace(/'(?:[^']|'')*'/g, "''")
        .replace(/"(?:[^"]|"")*"/g, '""');
}

const FROM_REGEX = /\bFROM\s+([a-zA-Z_][\w]*(?:\.[a-zA-Z_][\w]*)?)/gi;
const JOIN_REGEX = /\bJOIN\s+([a-zA-Z_][\w]*(?:\.[a-zA-Z_][\w]*)?)/gi;

function stripSchema(name) {
    const dot = name.indexOf('.');
    return dot === -1 ? name : name.substring(dot + 1);
}

/**
 * Extract candidate table names from a SQL string.
 *
 * @param {string} sqlText - SQL query string (single statement or multi-CTE)
 * @returns {Set<string>} - lowercase candidate table names
 */
function extractTables(sqlText) {
    if (typeof sqlText !== 'string' || sqlText.trim() === '') {
        return new Set();
    }
    const cleaned = stripCommentsAndStrings(sqlText);
    const candidates = new Set();
    let m;
    FROM_REGEX.lastIndex = 0;
    while ((m = FROM_REGEX.exec(cleaned)) !== null) {
        candidates.add(stripSchema(m[1]).toLowerCase());
    }
    JOIN_REGEX.lastIndex = 0;
    while ((m = JOIN_REGEX.exec(cleaned)) !== null) {
        candidates.add(stripSchema(m[1]).toLowerCase());
    }
    return candidates;
}

/**
 * Extract candidate table names from multiple SQL strings, returning the union set.
 *
 * @param {string[]} sqlTexts
 * @returns {Set<string>}
 */
function extractTablesUnion(sqlTexts) {
    const all = new Set();
    for (const sql of sqlTexts) {
        for (const t of extractTables(sql)) all.add(t);
    }
    return all;
}

module.exports = {
    extractTables,
    extractTablesUnion,
    // exposed untuk testing edge case
    _stripCommentsAndStrings: stripCommentsAndStrings
};
