/**
 * Shared function analysis helpers.
 *
 * Historical note: this module previously contained regex-based implementations
 * of buildFunctionScopes, buildUserDefinedFunctionCatalog, and
 * findDuplicateFunctionDeclarations. These have been superseded by the AST-based
 * equivalents in documentFacts.js and were removed in the v2 review remediation.
 *
 * What remains:
 *   getFunctionScopeAtLine      — pure lookup, no parsing dependency
 *   findBuiltinCollisionDeclarations — no AST equivalent yet; stays here until
 *                                      documentFacts.js grows a builtinCollisions fact
 */

import { parseFunctionDeclaration } from "../parser.js";
import { BuiltInFunctions } from "../builtins/functions.js";

/**
 * Gets the function scope that contains a line.
 * @param {Array} functionScopes - Scope list (from documentFacts.functionScopes)
 * @param {number} lineIndex - 0-based line index
 * @returns {object|null}
 */
function getFunctionScopeAtLine(functionScopes, lineIndex) {
    return functionScopes.find((scope) => lineIndex >= scope.startLine && lineIndex <= scope.endLine) || null;
}

/**
 * Finds user-defined function declarations that collide with built-in function names.
 * A declaration is exempt when it is wrapped in `IF NOT SYMBOL('name') ... ENDIF`
 * where 'name' matches the declared function name (case-insensitive).
 * @param {object} document
 * @returns {Array<{functionName:string,lineIndex:number,isCollision:boolean}>}
 */
function findBuiltinCollisionDeclarations(document) {
    const result = [];
    const symbolGuardStack = [];
    const controlFlowStack = [];

    for (let lineIndex = 0; lineIndex < document.lineCount; lineIndex += 1) {
        const lineText = document.lineAt(lineIndex).text;
        const trimmed = lineText.trim();

        const guardMatch = trimmed.match(/^IF\s+NOT\s*SYMBOL\s*\(\s*['"]([^'"]+)['"]\s*\)/i);
        if (guardMatch) {
            symbolGuardStack.push(guardMatch[1].toUpperCase());
            controlFlowStack.push(true);
        } else if (/^IF\b/i.test(trimmed)) {
            controlFlowStack.push(false);
        } else if (/^ENDIF\b/i.test(trimmed)) {
            const wasGuard = controlFlowStack.pop();
            if (wasGuard && symbolGuardStack.length > 0) {
                symbolGuardStack.pop();
            }
        }

        const declaration = parseFunctionDeclaration(lineText);
        if (!declaration) continue;
        if (!(declaration.upperName in BuiltInFunctions)) continue;

        const activeGuard = symbolGuardStack.length > 0 ? symbolGuardStack[symbolGuardStack.length - 1] : null;
        const isSymbolGuarded = activeGuard === declaration.upperName;

        result.push({
            functionName: declaration.upperName,
            lineIndex,
            isCollision: !isSymbolGuarded
        });
    }

    return result;
}

export {
    getFunctionScopeAtLine,
    findBuiltinCollisionDeclarations
};
