'use strict';

/**
 * Port dari packages/designer/src/migrators/sql_parser.rs.
 * Regex-based parser untuk SELECT/JOIN dari `datatablesQuery` string.
 */

const SELECT_RE = /select\s+([\s\S]*?)\s+from\s+/i;
const FROM_RE = /\bfrom\s+([\s\S]*)/i;
const JOIN_SPLIT_RE = /\b(left\s+join|inner\s+join|right\s+join|cross\s+join|join)\b/i;
const JOIN_SPLIT_RE_GLOBAL = /\b(left\s+join|inner\s+join|right\s+join|cross\s+join|join)\b/ig;
const WHERE_SPLIT_RE = /\s+where\s+/i;
const ORDER_SPLIT_RE = /\s+order\s+/i;
const ON_CLAUSE_RE = /([\s\S]*?)\s+on\s+([\s\S]*)/i;
const JOIN_COND_RE = /(\w+)\.(\w+)\s*=\s*(\w+)\.(\w+)/;

function stripSchema(name) {
    const idx = name.lastIndexOf('.');
    return idx >= 0 ? name.slice(idx + 1) : name;
}

function parseTableRef(refstr) {
    const afterWhere = refstr.split(WHERE_SPLIT_RE)[0].trim();
    const cleaned = afterWhere.split(ORDER_SPLIT_RE)[0].trim();
    const tokens = cleaned.split(/\s+/).filter(Boolean);
    if (tokens.length === 0) return { tableName: '', alias: '' };
    const tableName = stripSchema(tokens[0]);
    const alias = tokens.length > 1 ? tokens[1] : '';
    return { tableName, alias };
}

function parseJoinCondition(condition, mainAlias) {
    const m = JOIN_COND_RE.exec(condition.trim());
    if (!m) return { localColumn: '', remoteColumn: '' };
    const alias1 = m[1];
    const col1 = m[2];
    const col2 = m[4];
    if (alias1 === mainAlias) {
        return { localColumn: col1, remoteColumn: col2 };
    }
    return { localColumn: col2, remoteColumn: col1 };
}

function parseDatatablesQuery(sql) {
    const trimmed = String(sql || '').trim();
    if (!trimmed) {
        return { selectColumns: [], joins: [], mainTable: '', mainAlias: '' };
    }
    const sqlClean = trimmed.replace(/;+\s*$/, '');

    const selectMatch = SELECT_RE.exec(sqlClean);
    if (!selectMatch) {
        return { selectColumns: [], joins: [], mainTable: '', mainAlias: '' };
    }

    const columnsStr = selectMatch[1];
    const rawColumns = columnsStr.split(',');
    const selectColumns = [];
    for (let i = 0; i < rawColumns.length; i++) {
        const col = rawColumns[i].trim();
        if (!col) continue;
        const parts = col.split('.');
        let tableAlias = '';
        let name;
        if (parts.length >= 2) {
            tableAlias = parts[parts.length - 2].trim();
            name = parts[parts.length - 1].trim();
        } else {
            name = parts[0].trim();
        }
        selectColumns.push({ name, tableAlias, position: i + 1 });
    }

    const fromMatch = FROM_RE.exec(sqlClean);
    if (!fromMatch) {
        return { selectColumns, joins: [], mainTable: '', mainAlias: '' };
    }
    const fromClause = fromMatch[1];

    // Python re.split with capture group returns [before, kw, body, kw, body, ...]
    const parts = [];
    let lastEnd = 0;
    JOIN_SPLIT_RE_GLOBAL.lastIndex = 0;
    let match;
    while ((match = JOIN_SPLIT_RE_GLOBAL.exec(fromClause)) !== null) {
        parts.push(fromClause.slice(lastEnd, match.index));
        parts.push(match[0]);
        lastEnd = match.index + match[0].length;
    }
    parts.push(fromClause.slice(lastEnd));

    const mainRef = parseTableRef(parts[0] || '');
    const mainTable = mainRef.tableName;
    const mainAlias = mainRef.alias;

    const joins = [];
    let j = 1;
    while (j + 1 < parts.length) {
        const joinBody = parts[j + 1].trim();
        const onMatch = ON_CLAUSE_RE.exec(joinBody);
        if (!onMatch) {
            j += 2;
            continue;
        }
        const tableRef = onMatch[1];
        const condition = onMatch[2];
        const ref = parseTableRef(tableRef);
        const cond = parseJoinCondition(condition, mainAlias);
        joins.push({
            tableName: ref.tableName,
            tableAlias: ref.alias,
            localColumn: cond.localColumn,
            remoteColumn: cond.remoteColumn
        });
        j += 2;
    }

    return { selectColumns, joins, mainTable, mainAlias };
}

module.exports = {
    parseDatatablesQuery,
    stripSchema
};
