/**
 * Hover provider for Acurity Architect variables, functions, and DB fields.
 */

import * as vscode from "vscode";
import { LANGUAGE_ID } from "../../core/src/constants.js";
import { parseVarDeclaration, parseAssignment, stripTrailingComment, parseFunctionDeclaration, extractArgAt } from "../../core/src/parser.js";
import { getExpectedTypeFromName, getRecommendedPrefix } from "../../core/src/types/acurityTypes.js";
import { getFunctionSignature, BuiltInFunctions } from "../../core/src/builtins/functions.js";
import { collectDocumentFacts } from "../../core/src/analysis/documentFacts.js";
import { extractMacroInvocations } from "../../core/src/analysis/macroAnalysis.js";
import { getCatalogEntry } from "../../core/src/diagnostics/diagnosticCatalog.js";
import { buildHandleBindingsAtLine } from "../../core/src/analysis/handleBindingAnalysis.js";
import { getTableEntry } from "../../core/src/builtins/tableSynonymsRegistry.js";
import { getTableStructure } from "../../core/src/builtins/tableStructureRegistry.js";
import { buildLoadPositionsAtLine, resolveFieldInStructure, TYPE_TO_LOAD_KEY_SUFFIX } from "../../core/src/analysis/indexLoadPositionAnalysis.js";

/**
 * Initializes the hover provider.
 * @param {vscode.ExtensionContext} context - The extension context
 */
function initializeHoverProvider(context) {
    const hoverProvider = vscode.languages.registerHoverProvider(
        LANGUAGE_ID,
        {
            provideHover(document, position) {
                return provideVariableHover(document, position);
            }
        }
    );

    context.subscriptions.push(hoverProvider);
}

/**
 * Provides hover information for the symbol at the given position.
 * @param {vscode.TextDocument} document - The document
 * @param {vscode.Position} position - The cursor position
 * @returns {Promise<vscode.Hover|null>}
 */
async function provideVariableHover(document, position) {
    // Check first whether the cursor is over a rule ID inside a @rule-ignore comment
    const ruleIgnoreHover = provideRuleIgnoreHover(document, position);
    if (ruleIgnoreHover) {
        return ruleIgnoreHover;
    }

    const range = document.getWordRangeAtPosition(position, /[A-Za-z_][A-Za-z0-9_]*/);
    if (!range) {
        return null;
    }

    const word = document.getText(range);
    const lineText = document.lineAt(position.line).text;
    const wordEnd = range.end.character;

    // Get document facts including macro catalog
    const facts = collectDocumentFacts(document);

    // Check if it's a macro invocation
    const invocations = extractMacroInvocations(lineText, facts.macroCatalog);
    const macroInvocation = invocations.find(inv => inv.name === word && inv.startPos <= position.character && position.character <= inv.endPos);
    if (macroInvocation) {
        return provideMacroHover(macroInvocation.name, range, facts.macroCatalog);
    }

    // Check if it's a function
    if (wordEnd < lineText.length && lineText[wordEnd] === "(") {
        const handleBindings = buildHandleBindingsAtLine(document, position.line);
        const loadPositions = buildLoadPositionsAtLine(document, position.line);
        return await provideFunctionHover(word, range, lineText, position.character, handleBindings, loadPositions, document, position.line);
    }

    // Check if it looks like a DB field reference (features 7)
    const fieldHover = await provideFieldReferenceHover(word, range);
    if (fieldHover) {
        return fieldHover;
    }

    // Otherwise treat as variable
    const variableInfo = findVariableInfo(document, word, position.line);
    if (!variableInfo) {
        return null;
    }

    const handleBindings = buildHandleBindingsAtLine(document, position.line);
    const loadPositions = buildLoadPositionsAtLine(document, position.line);
    const boundTableCode = handleBindings.get(word.toLowerCase());
    const boundIndexState = loadPositions.get(word.toLowerCase());

    const markdownContent = await buildVariableHoverContent(variableInfo, boundTableCode, boundIndexState);
    return new vscode.Hover(markdownContent, range);
}

/** Matches individual ACU-DOMAIN-NNN tokens (e.g. ACU-VAR-001) */
const ACU_ID_TOKEN_RE = /\bACU-[A-Z]+-\d{3}\b/g;

/**
 * If the cursor is on an ACU-XXX-NNN token inside a `// @rule-ignore` comment,
 * returns a Hover showing the rule's message template. Otherwise returns null.
 */
function provideRuleIgnoreHover(document, position) {
    const lineText = document.lineAt(position.line).text;
    if (!/@rule-ignore/i.test(lineText)) {
        return null;
    }

    ACU_ID_TOKEN_RE.lastIndex = 0;
    let match;
    while ((match = ACU_ID_TOKEN_RE.exec(lineText)) !== null) {
        const start = match.index;
        const end = start + match[0].length;
        if (position.character < start || position.character > end) {
            continue;
        }

        const messageId = match[0].toUpperCase();
        const entry = getCatalogEntry(messageId);

        const hoverRange = new vscode.Range(
            new vscode.Position(position.line, start),
            new vscode.Position(position.line, end)
        );

        const content = new vscode.MarkdownString();
        content.supportHtml = false;

        if (!entry) {
            content.appendMarkdown(`**${messageId}** — _(unknown rule)_`);
        } else {
            content.appendMarkdown(`**${messageId}** \`${entry.ruleId}\`\n\n`);
            content.appendText(entry.message);
        }

        return new vscode.Hover(content, hoverRange);
    }

    return null;
}

// ---------------------------------------------------------------------------
// Feature 7: field reference hover
// ---------------------------------------------------------------------------

/**
 * Detects whether `word` looks like a DB field name and, if so, returns hover
 * content showing its type and index appearances.
 *
 * Recognised patterns:
 *   hXXy_...  — handle/output form  (e.g. hRAz_Division)
 *   XXy_...   — raw index-segment form (e.g. RAz_Division)
 *
 * @param {string} word
 * @param {vscode.Range} range
 * @returns {Promise<vscode.Hover|null>}
 */
async function provideFieldReferenceHover(word, range) {
    let tableCode = null;

    if (/^h[A-Z]{2}[a-z_]/.test(word)) {
        tableCode = word.slice(1, 3).toUpperCase();
    } else if (/^[A-Z]{2}[a-z_]/.test(word)) {
        tableCode = word.slice(0, 2).toUpperCase();
    }

    if (!tableCode) {
        return null;
    }

    const structure = await getTableStructure(tableCode);
    if (!structure) {
        return null;
    }

    const fieldInfo = resolveFieldInStructure(structure, word);
    if (!fieldInfo) {
        return null;
    }

    const te = getTableEntry(tableCode);
    const tableLabel = te ? `${tableCode} (${te.name})` : tableCode;

    const markdown = new vscode.MarkdownString();
    markdown.isTrusted = true;

    markdown.appendCodeblock(`${fieldInfo.canonical} : ${fieldInfo.type}`, "acurity");
    markdown.appendMarkdown(`\n**Table:** ${tableLabel}\n`);

    if (fieldInfo.appearances.length > 0) {
        markdown.appendMarkdown(`\n**Appears in indexes:**\n`);
        for (const ap of fieldInfo.appearances) {
            markdown.appendMarkdown(`- Index \`"${ap.indexName}"\` position ${ap.position} — ${ap.type}(${ap.length})\n`);
        }
    } else {
        markdown.appendMarkdown(`\n_Not found in any index segment._\n`);
    }

    return new vscode.Hover(markdown, range);
}

// ---------------------------------------------------------------------------
// Function hover (features 1 & 2)
// ---------------------------------------------------------------------------

/**
 * Provides hover information for built-in functions.
 *
 * Enhanced for index functions:
 *   Feature 1 — INDEX_OPEN_STANDARD: shows the index schema (segments).
 *   Feature 2 — INDEX_LOAD_KEY_*: shows the current segment being loaded.
 *
 * @param {string} functionName
 * @param {vscode.Range} range
 * @param {string} lineText
 * @param {number} charPos
 * @param {Map<string,string>} handleBindings   handle→tableCode
 * @param {Map<string,{tableCode,indexName,nextLoadPosition}>} loadPositions
 * @param {vscode.TextDocument} document
 * @param {number} lineIndex
 * @returns {Promise<vscode.Hover|null>}
 */
async function provideFunctionHover(functionName, range, lineText, charPos, handleBindings, loadPositions, document, lineIndex) {
    const signature = getFunctionSignature(functionName);
    if (!signature) {
        return null;
    }

    const markdown = new vscode.MarkdownString();
    markdown.isTrusted = true;

    // Standard signature block
    const formatParamType = (p) => Array.isArray(p) ? p.join("|") : p;
    const getParamLabel = (i) => (signature.paramLabels && signature.paramLabels[i]) ? signature.paramLabels[i] : `param${i + 1}`;
    const paramList = signature.params.map((p, i) => `${getParamLabel(i)}: ${formatParamType(p)}`).join(", ");
    markdown.appendCodeblock(`${functionName}(${paramList}) : ${signature.returns}`, "acurity");

    if (signature.description) {
        markdown.appendMarkdown(`\n${signature.description}\n`);
    }

    if (signature.params.length > 0) {
        markdown.appendMarkdown(`\n**Parameters:**\n`);
        signature.params.forEach((param, i) => {
            markdown.appendMarkdown(`- \`${getParamLabel(i)}\`: ${formatParamType(param)}\n`);
        });
    }

    markdown.appendMarkdown(`\n**Returns:** ${signature.returns}\n`);

    if (signature.varArgs) {
        markdown.appendMarkdown(`\n*This function accepts variable arguments.*\n`);
    }

    // Cursor table information (existing logic)
    const entry = BuiltInFunctions[functionName.toUpperCase()];
    if (entry) {
        if (entry.cursorTables) {
            const tableList = entry.cursorTables.map(code => {
                const te = getTableEntry(code);
                return te ? `${code} (${te.name})` : code;
            }).join(", ");
            markdown.appendMarkdown(`\n**Advances cursor on:** ${tableList}\n`);
        } else if (entry.cursorTableFromHandle !== undefined && lineText && handleBindings) {
            const callStart = lineText.lastIndexOf(functionName, charPos);
            if (callStart !== -1) {
                const handleArg = extractArgAt(lineText.slice(callStart), entry.cursorTableFromHandle);
                if (handleArg) {
                    const tableCode = handleBindings.get(handleArg.trim().toLowerCase());
                    if (tableCode) {
                        const te = getTableEntry(tableCode);
                        const label = te ? `${tableCode} (${te.name})` : tableCode;
                        markdown.appendMarkdown(`\n**Advances cursor on:** ${label}\n`);
                    }
                }
            }
        }
    }

    const upperName = functionName.toUpperCase();

    // -----------------------------------------------------------------------
    // Feature 1: INDEX_OPEN_STANDARD / SQL_INDEX_OPEN_STANDARD — show the index schema
    // -----------------------------------------------------------------------
    if (upperName === "INDEX_OPEN_STANDARD" || upperName === "SQL_INDEX_OPEN_STANDARD") {
        const callStart = lineText.toUpperCase().indexOf(upperName);
        if (callStart !== -1) {
            const callExpr = lineText.slice(callStart);
            const tableArg = extractArgAt(callExpr, 0);
            const indexArg = extractArgAt(callExpr, 1);

            if (tableArg && indexArg) {
                const tableMatch = tableArg.trim().match(/^["']([^"']+)["']$/);
                const indexName = indexArg.trim().replace(/^["']|["']$/g, "");

                if (tableMatch) {
                    const tableCode = tableMatch[1].toUpperCase();
                    const structure = await getTableStructure(tableCode);

                    if (structure) {
                        const index = structure.indexes.find(idx => idx.name === indexName);
                        const te = getTableEntry(tableCode);
                        const tableLabel = te ? `${tableCode} (${te.name})` : tableCode;

                        markdown.appendMarkdown(`\n---\n\n**Table:** ${tableLabel}\n`);

                        if (index) {
                            const dupeFlag = index.duplicates ? "duplicates allowed" : "unique";
                            const modFlag = index.modifiable ? ", modifiable" : "";
                            markdown.appendMarkdown(`**Index** \`"${indexName}"\` — ${dupeFlag}${modFlag}\n\n`);
                            markdown.appendMarkdown(`| Pos | Field | Type | Length |\n`);
                            markdown.appendMarkdown(`|-----|-------|------|--------|\n`);
                            for (const seg of index.segments) {
                                markdown.appendMarkdown(`| ${seg.position} | \`${seg.field}\` | ${seg.type} | ${seg.length} |\n`);
                            }
                        } else {
                            const availableNames = structure.indexes.map(i => `"${i.name}"`).join(", ");
                            markdown.appendMarkdown(`**Index** \`"${indexName}"\` — _not found on ${tableCode}._\n`);
                            markdown.appendMarkdown(`Available indexes: ${availableNames}\n`);
                        }
                    }
                }
            }
        }
    }

    // -----------------------------------------------------------------------
    // Feature 2: INDEX_LOAD_KEY_* / SQL_INDEX_LOAD_KEY_* — show the segment being loaded
    // -----------------------------------------------------------------------
    if (upperName.startsWith("INDEX_LOAD_KEY_") || upperName.startsWith("SQL_INDEX_LOAD_KEY_")) {
        const callStart = lineText.toUpperCase().indexOf(upperName);
        if (callStart !== -1) {
            const callExpr = lineText.slice(callStart);
            const handleArg = extractArgAt(callExpr, 0);

            if (handleArg) {
                const handleVar = handleArg.trim().toLowerCase();
                const state = loadPositions.get(handleVar);

                if (state) {
                    const structure = await getTableStructure(state.tableCode);
                    if (structure) {
                        const index = structure.indexes.find(idx => idx.name === state.indexName);
                        if (index) {
                            const pos = state.nextLoadPosition;
                            const te = getTableEntry(state.tableCode);
                            const tableLabel = te ? `${state.tableCode} (${te.name})` : state.tableCode;

                            markdown.appendMarkdown(`\n---\n\n**Table:** ${tableLabel} · Index \`"${state.indexName}"\`\n\n`);

                            if (pos >= index.segments.length) {
                                markdown.appendMarkdown(`⚠️ **Exceeds segment count** — index has only ${index.segments.length} segment${index.segments.length !== 1 ? "s" : ""}.\n`);
                            } else {
                                const seg = index.segments[pos];
                                const expectedSuffix = TYPE_TO_LOAD_KEY_SUFFIX[seg.type] || seg.type;
                                const loadKeyPrefix = upperName.startsWith("SQL_") ? "SQL_INDEX_LOAD_KEY_" : "INDEX_LOAD_KEY_";
                                const actualSuffix = upperName.slice(loadKeyPrefix.length);
                                const typeMatch = actualSuffix === expectedSuffix;

                                markdown.appendMarkdown(`**Loading segment ${pos} of ${index.segments.length}:**\n`);
                                markdown.appendMarkdown(`- Field: \`${seg.field}\`\n`);
                                markdown.appendMarkdown(`- Type: ${seg.type}(${seg.length})`);
                                markdown.appendMarkdown(typeMatch ? ` ✅\n` : ` — ⚠️ expected \`${loadKeyPrefix}${expectedSuffix}\`\n`);

                                const remaining = index.segments.slice(pos + 1);
                                if (remaining.length > 0) {
                                    markdown.appendMarkdown(`\n**Remaining segments:**\n`);
                                    for (const rem of remaining) {
                                        markdown.appendMarkdown(`- ${rem.position}: \`${rem.field}\` — ${rem.type}(${rem.length})\n`);
                                    }
                                } else {
                                    markdown.appendMarkdown(`\n_This is the last segment._\n`);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return new vscode.Hover(markdown, range);
}

// ---------------------------------------------------------------------------
// Macro hover (unchanged)
// ---------------------------------------------------------------------------

function provideMacroHover(macroName, range, macroCatalog) {
    const upperName = macroName.toUpperCase();
    const macroEntry = macroCatalog[upperName];

    if (!macroEntry) {
        return null;
    }

    const markdown = new vscode.MarkdownString();
    markdown.isTrusted = true;

    const paramList = macroEntry.params.length > 0
        ? `(${macroEntry.params.join(", ")})`
        : "";
    markdown.appendCodeblock(`MACRO ${macroName}${paramList}`, "acurity");

    markdown.appendMarkdown(`\n**Expands to:**\n`);
    markdown.appendCodeblock(macroEntry.body, "text");

    if (macroEntry.params.length > 0) {
        markdown.appendMarkdown(`\n**Parameters:** ${macroEntry.params.length}\n`);
        macroEntry.params.forEach((param) => {
            markdown.appendMarkdown(`- \`${param}\`\n`);
        });
    } else {
        markdown.appendMarkdown(`\n**Parameters:** None (compile-time constant)\n`);
    }

    markdown.appendMarkdown(`\n**Declared at:** line ${macroEntry.lineIndex + 1}\n`);

    return new vscode.Hover(markdown, range);
}

// ---------------------------------------------------------------------------
// Variable info lookup (unchanged)
// ---------------------------------------------------------------------------

function findVariableInfo(document, variableName, currentLine) {
    let declarationLine = -1;
    let variableType = "UNKNOWN";
    let isInitialized = false;
    let initialValue = null;
    let isFunctionParameter = false;
    let isFunctionScoped = false;
    let functionScopeStart = -1;
    let functionScopeEnd = -1;

    const functionScopes = [];
    let currentScope = null;

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

        if (!currentScope) {
            const funcDecl = parseFunctionDeclaration(lineText);
            if (funcDecl) {
                currentScope = {
                    startLine: lineIndex,
                    endLine: document.lineCount - 1,
                    params: funcDecl.params
                };
            }
        }

        if (currentScope && /^\s*#?\s*ENDFUNCTION\b/i.test(lineText)) {
            currentScope.endLine = lineIndex;
            functionScopes.push(currentScope);
            currentScope = null;
        }
    }

    if (currentScope) {
        functionScopes.push(currentScope);
    }

    for (const scope of functionScopes) {
        const param = scope.params.find(p => p.name === variableName);
        if (param) {
            isFunctionParameter = true;
            isFunctionScoped = true;
            declarationLine = scope.startLine;
            variableType = param.type;
            functionScopeStart = scope.startLine;
            functionScopeEnd = scope.endLine;
            break;
        }
    }

    if (!isFunctionParameter) {
        for (let lineIndex = 0; lineIndex < document.lineCount; lineIndex += 1) {
            const lineText = document.lineAt(lineIndex).text;
            const declaration = parseVarDeclaration(lineText);
            if (declaration && declaration.variables.includes(variableName)) {
                declarationLine = lineIndex;
                variableType = declaration.type;

                for (const scope of functionScopes) {
                    if (lineIndex > scope.startLine && lineIndex <= scope.endLine) {
                        isFunctionScoped = true;
                        functionScopeStart = scope.startLine;
                        functionScopeEnd = scope.endLine;
                        break;
                    }
                }
                break;
            }
        }
    }

    for (let lineIndex = 0; lineIndex < currentLine; lineIndex += 1) {
        const lineText = document.lineAt(lineIndex).text;
        const assignment = parseAssignment(lineText);
        if (assignment && assignment.target === variableName) {
            isInitialized = true;
            initialValue = assignment.expression.trim();
        }
    }

    if (declarationLine === -1) {
        return null;
    }

    return {
        name: variableName,
        type: variableType,
        declarationLine,
        isInitialized,
        initialValue,
        isFunctionParameter,
        isFunctionScoped,
        functionScopeStart,
        functionScopeEnd
    };
}

function buildCharToTypeMap() {
    const config = vscode.workspace.getConfiguration("acurity.naming");
    const charToType = {};

    const stringPrefix  = config.get("typePrefixes.string.prefixChar")  || "z";
    const shortPrefix   = config.get("typePrefixes.short.prefixChar")   || "s";
    const longPrefix    = config.get("typePrefixes.long.prefixChar")    || "l";
    const doublePrefix  = config.get("typePrefixes.double.prefixChar")  || "f";
    const booleanPrefix = config.get("typePrefixes.boolean.prefixChar") || "b";
    const datePrefix    = config.get("typePrefixes.date.prefixChar")    || "d";
    const timePrefix    = config.get("typePrefixes.time.prefixChar")    || "t";

    if (stringPrefix)  charToType[stringPrefix.toLowerCase()]  = "STRING";
    if (shortPrefix)   charToType[shortPrefix.toLowerCase()]   = "SHORT";
    if (longPrefix)    charToType[longPrefix.toLowerCase()]    = "LONG";
    if (doublePrefix)  charToType[doublePrefix.toLowerCase()]  = "DOUBLE";
    if (booleanPrefix) charToType[booleanPrefix.toLowerCase()] = "BOOLEAN";
    if (datePrefix)    charToType[datePrefix.toLowerCase()]    = "DATE";
    if (timePrefix)    charToType[timePrefix.toLowerCase()]    = "TIME";

    return charToType;
}

// ---------------------------------------------------------------------------
// Feature 3: variable hover with active index enrichment
// ---------------------------------------------------------------------------

/**
 * Builds hover content for a variable.
 *
 * Feature 3: when the variable is an index handle, also shows the active
 * index name and a compact segment summary.
 *
 * @param {object} variableInfo
 * @param {string|undefined} boundTableCode   From handleBindings (table only)
 * @param {{tableCode,indexName,nextLoadPosition}|undefined} boundIndexState  From loadPositions
 * @returns {Promise<vscode.MarkdownString>}
 */
async function buildVariableHoverContent(variableInfo, boundTableCode, boundIndexState) {
    const markdown = new vscode.MarkdownString();
    markdown.isTrusted = true;

    markdown.appendCodeblock(`VAR ${variableInfo.name} : ${variableInfo.type}`, "acurity");

    if (variableInfo.isFunctionParameter) {
        markdown.appendMarkdown(`\n**Scope:** Function parameter\n`);
    } else if (variableInfo.isFunctionScoped) {
        markdown.appendMarkdown(`\n**Scope:** Function-scoped variable\n`);
    } else {
        markdown.appendMarkdown(`\n**Scope:** Global variable\n`);
    }

    markdown.appendMarkdown(`**Declared at:** line ${variableInfo.declarationLine + 1}\n\n`);

    // Handle binding — show table + active index (feature 3)
    if (boundTableCode) {
        const te = getTableEntry(boundTableCode);
        const tableLabel = te ? `${boundTableCode} (${te.name})` : boundTableCode;
        markdown.appendMarkdown(`**Bound to table:** ${tableLabel}\n\n`);

        if (boundIndexState && boundIndexState.indexName !== undefined) {
            const structure = await getTableStructure(boundIndexState.tableCode || boundTableCode);
            if (structure) {
                const index = structure.indexes.find(idx => idx.name === boundIndexState.indexName);
                if (index) {
                    const segSummary = index.segments.map(s => s.field).join(", ");
                    markdown.appendMarkdown(`**Active index:** \`"${boundIndexState.indexName}"\` — ${index.segments.length} segment${index.segments.length !== 1 ? "s" : ""}\n`);
                    markdown.appendMarkdown(`> ${segSummary}\n\n`);
                }
            }
        }
    }

    // Naming convention check
    const charToTypeMap = buildCharToTypeMap();

    let prefixChars = [];
    if (variableInfo.name && variableInfo.name.length > 0) {
        const firstChar = variableInfo.name[0].toLowerCase();
        prefixChars.push(firstChar);
        if (variableInfo.name.length > 1) {
            const secondChar = variableInfo.name[1].toLowerCase();
            if (secondChar >= "a" && secondChar <= "z") {
                prefixChars.push(secondChar);
            }
        }
    }

    for (const prefixChar of prefixChars) {
        const expectedType = charToTypeMap[prefixChar];
        if (expectedType && expectedType !== variableInfo.type) {
            const scopeToCharMap = {
                "global": (vscode.workspace.getConfiguration("acurity.naming").get("scopePrefixes.global.prefixChar") || "g").toLowerCase(),
                "parameter": (vscode.workspace.getConfiguration("acurity.naming").get("scopePrefixes.parameter.prefixChar") || "p").toLowerCase(),
                "function-scoped": (vscode.workspace.getConfiguration("acurity.naming").get("scopePrefixes.functionScoped.prefixChar") || "f").toLowerCase()
            };
            const isFunctionParameter = variableInfo.isFunctionParameter || false;
            const isFunctionScoped = variableInfo.isFunctionScoped && !isFunctionParameter;
            const scopeKey = isFunctionParameter ? "parameter" : (isFunctionScoped ? "function-scoped" : "global");
            const scopeChar = scopeToCharMap[scopeKey];
            const typeChar = Object.entries(charToTypeMap).find(([ch, type]) => type === variableInfo.type)?.[0] || "x";
            const recommendedPrefix = scopeChar + typeChar;
            const upperIdx = variableInfo.name.search(/[A-Z]/);
            const stemStart = upperIdx >= 0 ? upperIdx : Math.min(2, variableInfo.name.length);
            const recommendedName = recommendedPrefix + variableInfo.name.substring(stemStart);
            markdown.appendMarkdown(`⚠️ **Naming:** Prefix suggests ${expectedType}, consider \`${recommendedName}\`\n\n`);
            break;
        }
    }

    if (variableInfo.isInitialized) {
        markdown.appendMarkdown(`**Status:** ✅ Initialized\n\n`);
        if (variableInfo.initialValue) {
            markdown.appendMarkdown(`**Last value:** \`${variableInfo.initialValue}\`\n`);
        }
    } else {
        markdown.appendMarkdown(`**Status:** ⚠️ Not initialized\n`);
    }

    return markdown;
}

export {
    initializeHoverProvider
};
