/*
 * 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.
 */
import { DiagnosticSeverity } from 'vscode-languageserver';
import { getEntry, isIndexLoaded, getAllApiNames } from '../index-loader.js';
// ─── Constants ────────────────────────────────────────────────────────────────
const DIAGNOSTIC_SOURCE = 'sf-metadata-lsp';
/**
 * Pattern for tokens that look like Salesforce API names.
 * Matches names containing __c, __e, __mdt, __b, __x suffixes.
 */
const API_NAME_SUFFIXES = ['__c', '__e', '__mdt', '__b', '__x', '__r'];
/**
 * Maximum number of diagnostics per document to avoid performance issues.
 */
const MAX_DIAGNOSTICS = 50;
// ─── Diagnostics Handler ──────────────────────────────────────────────────────
/**
 * Generates diagnostics for a document on open/save.
 * Reports warnings for references to API names that do not exist in the index.
 * Only flags tokens that clearly look like Salesforce API names.
 */
export function computeDiagnostics(document) {
    if (!isIndexLoaded())
        return [];
    const extension = getFileExtension(document.uri);
    const supportedExtensions = new Set(['.cls', '.trigger', '.js', '.ts', '.xml']);
    if (!supportedExtensions.has(extension))
        return [];
    const text = document.getText();
    const lines = text.split('\n');
    const knownNames = new Set(getAllApiNames());
    return collectUnresolvedReferences(lines, knownNames);
}
function collectUnresolvedReferences(lines, knownNames) {
    const diagnostics = [];
    for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
        if (diagnostics.length >= MAX_DIAGNOSTICS)
            break;
        collectLineDiagnostics(lines[lineIndex], lineIndex, knownNames, diagnostics);
    }
    return diagnostics;
}
function collectLineDiagnostics(line, lineIndex, knownNames, diagnostics) {
    const tokens = extractApiNameTokens(line);
    for (const token of tokens) {
        if (diagnostics.length >= MAX_DIAGNOSTICS)
            break;
        if (getEntry(token.text))
            continue;
        if (!isLikelyApiName(token.text, knownNames))
            continue;
        diagnostics.push({
            severity: DiagnosticSeverity.Warning,
            range: {
                start: { line: lineIndex, character: token.start },
                end: { line: lineIndex, character: token.start + token.text.length },
            },
            message: `Unresolved metadata reference: '${token.text}' is not found in the metadata index.`,
            source: DIAGNOSTIC_SOURCE,
        });
    }
}
function extractApiNameTokens(line) {
    const tokens = [];
    // Match word-like tokens that contain API name suffixes
    const pattern = /[A-Za-z][A-Za-z0-9_]*__[a-z]+/g;
    let match;
    while ((match = pattern.exec(line)) !== null) {
        tokens.push({ text: match[0], start: match.index });
    }
    return tokens;
}
// ─── Validation ───────────────────────────────────────────────────────────────
function isLikelyApiName(token, knownNames) {
    // Must have one of the known SF suffixes
    const hasSuffix = API_NAME_SUFFIXES.some((suffix) => token.endsWith(suffix));
    if (!hasSuffix) {
        return false;
    }
    // Skip if it's a standard Salesforce object (Account, Contact, etc.)
    // These wouldn't have __c suffix so this check is just for safety
    if (token.length < 3) {
        return false;
    }
    // If the token looks like a qualified field (Object__c.Field__c), check the object part too
    if (token.includes('.')) {
        const parts = token.split('.');
        // If the object exists but field doesn't, still flag it
        const objectPart = parts[0];
        if (knownNames.has(objectPart)) {
            // Object exists, field might not — flag the field reference
            return true;
        }
    }
    return true;
}
// ─── Helpers ──────────────────────────────────────────────────────────────────
function getFileExtension(uri) {
    const dotIndex = uri.lastIndexOf('.');
    if (dotIndex === -1)
        return '';
    return uri.slice(dotIndex);
}
//# sourceMappingURL=diagnostics.js.map