/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// ─── Detection ────────────────────────────────────────────────────────────────
/**
 * Determines the semantic context at a given position in a document.
 * Uses simple line-based heuristics (no full AST parsing).
 */
export function detectContext(lineText, character, fileExtension, allLines) {
    const textBeforeCursor = lineText.slice(0, character);
    if (fileExtension === '.js' || fileExtension === '.ts') {
        return detectLwcContext(textBeforeCursor);
    }
    if (fileExtension === '.cls') {
        return detectApexContext(textBeforeCursor, allLines);
    }
    if (fileExtension === '.trigger') {
        return detectTriggerContext(textBeforeCursor);
    }
    if (fileExtension === '.xml') {
        return detectXmlContext(textBeforeCursor);
    }
    return { kind: 'unknown', prefix: '' };
}
// ─── LWC Context ──────────────────────────────────────────────────────────────
function detectLwcContext(textBeforeCursor) {
    // @salesforce/apex/ClassName.method
    const apexImportMatch = textBeforeCursor.match(/@salesforce\/apex\/([A-Za-z0-9_.]*)$/);
    if (apexImportMatch) {
        return { kind: 'lwc:apex-import', prefix: apexImportMatch[1] };
    }
    // @salesforce/schema/Object.Field
    const schemaImportMatch = textBeforeCursor.match(/@salesforce\/schema\/([A-Za-z0-9_.]*)$/);
    if (schemaImportMatch) {
        return { kind: 'lwc:schema-import', prefix: schemaImportMatch[1] };
    }
    // Check if we're in a string that contains @salesforce/apex or @salesforce/schema
    const apexStringMatch = textBeforeCursor.match(/['"]@salesforce\/apex\/([A-Za-z0-9_.]*)$/);
    if (apexStringMatch) {
        return { kind: 'lwc:apex-import', prefix: apexStringMatch[1] };
    }
    const schemaStringMatch = textBeforeCursor.match(/['"]@salesforce\/schema\/([A-Za-z0-9_.]*)$/);
    if (schemaStringMatch) {
        return { kind: 'lwc:schema-import', prefix: schemaStringMatch[1] };
    }
    return { kind: 'unknown', prefix: '' };
}
// ─── Apex Context ─────────────────────────────────────────────────────────────
function detectApexContext(textBeforeCursor, allLines) {
    // Check if we're inside a SOQL query
    const soqlContext = detectSoqlContext(textBeforeCursor, allLines);
    if (soqlContext) {
        return soqlContext;
    }
    // Class reference patterns: new ClassName, ClassName variable, Type annotation
    const classRefMatch = textBeforeCursor.match(/(?:new\s+|:\s*|<|,\s*|extends\s+|implements\s+)([A-Z][A-Za-z0-9_]*)$/);
    if (classRefMatch) {
        return { kind: 'apex:class-reference', prefix: classRefMatch[1] };
    }
    // Method call on a type: ClassName.method(
    const staticCallMatch = textBeforeCursor.match(/([A-Z][A-Za-z0-9_]*)\.$/);
    if (staticCallMatch) {
        return { kind: 'apex:class-reference', prefix: staticCallMatch[1] };
    }
    // Variable declaration: ClassName varName
    const varDeclMatch = textBeforeCursor.match(/^\s*([A-Z][A-Za-z0-9_]*)$/);
    if (varDeclMatch) {
        return { kind: 'apex:class-reference', prefix: varDeclMatch[1] };
    }
    return { kind: 'unknown', prefix: '' };
}
function detectSoqlContext(textBeforeCursor, allLines) {
    // Simple check: are we in a SOQL string?
    const upperText = textBeforeCursor.toUpperCase();
    // Check if current line or surrounding lines contain a SOQL bracket [SELECT ...]
    const isInSoql = upperText.includes('[') && (upperText.includes('SELECT') || upperText.includes('FROM'));
    // Also check if we're in a multi-line SOQL by looking at surrounding lines
    if (!isInSoql) {
        const combinedText = allLines.join(' ').toUpperCase();
        const hasSoqlBracket = combinedText.includes('[') && combinedText.includes('SELECT');
        if (!hasSoqlBracket) {
            return null;
        }
        // Verify cursor is actually inside the SOQL block
        if (!upperText.includes('FROM') && !upperText.includes('SELECT') && !upperText.includes('WHERE')) {
            return null;
        }
    }
    // After FROM keyword
    const fromMatch = textBeforeCursor.match(/FROM\s+([a-z0-9_]*)$/i);
    if (fromMatch) {
        return { kind: 'apex:soql-from', prefix: fromMatch[1] };
    }
    // After SELECT or in field list (before FROM)
    const selectFieldMatch = textBeforeCursor.match(/(?:SELECT\s+|,\s*)([a-z0-9_.]*)$/i);
    if (selectFieldMatch) {
        // Try to find the FROM object in the same query
        const soqlObject = extractSoqlObject(allLines);
        return { kind: 'apex:soql-field', prefix: selectFieldMatch[1], soqlObject };
    }
    // After WHERE
    const whereFieldMatch = textBeforeCursor.match(/WHERE\s+([a-z0-9_.]*)$/i);
    if (whereFieldMatch) {
        const soqlObject = extractSoqlObject(allLines);
        return { kind: 'apex:soql-field', prefix: whereFieldMatch[1], soqlObject };
    }
    return null;
}
function extractSoqlObject(allLines) {
    const combinedText = allLines.join(' ');
    const fromMatch = combinedText.match(/FROM\s+([a-z0-9_]+)/i);
    return fromMatch?.[1];
}
// ─── Trigger Context ──────────────────────────────────────────────────────────
function detectTriggerContext(textBeforeCursor) {
    // trigger MyTrigger on ObjectName
    const triggerOnMatch = textBeforeCursor.match(/\bon\s+([a-z0-9_]*)$/i);
    if (triggerOnMatch) {
        return { kind: 'trigger:object', prefix: triggerOnMatch[1] };
    }
    return { kind: 'unknown', prefix: '' };
}
// ─── XML Context ──────────────────────────────────────────────────────────────
function detectXmlContext(textBeforeCursor) {
    // Inside an XML element value: <tagName>value</tagName>
    // Match text after the last > and before cursor
    const elementValueMatch = textBeforeCursor.match(/>([^<]*)$/);
    if (elementValueMatch) {
        return { kind: 'xml:element-value', prefix: elementValueMatch[1].trim() };
    }
    return { kind: 'unknown', prefix: '' };
}
// ─── Word Extraction ──────────────────────────────────────────────────────────
/**
 * Extracts the word at a given character position in a line.
 * Used for hover and go-to-definition.
 */
export function getWordAtPosition(lineText, character) {
    // Find word boundaries around the character position
    const wordPattern = /[A-Za-z0-9_]+/g;
    let match;
    while ((match = wordPattern.exec(lineText)) !== null) {
        const start = match.index;
        const end = start + match[0].length;
        if (character >= start && character < end) {
            return match[0];
        }
    }
    return '';
}
/**
 * Extracts a qualified name (e.g., Object__c.Field__c) at a given position.
 */
export function getQualifiedNameAtPosition(lineText, character) {
    // Find qualified name boundaries (includes dots)
    const qualifiedPattern = /[A-Za-z0-9_.]+/g;
    let match;
    while ((match = qualifiedPattern.exec(lineText)) !== null) {
        const start = match.index;
        const end = start + match[0].length;
        if (character >= start && character < end) {
            return match[0];
        }
    }
    return '';
}
//# sourceMappingURL=document-context.js.map