/**
 * Macro invocation validator for Acurity Architect.
 * Validates macro definitions, invocations, and parameter counts.
 */

import { createDiagnostic } from "../diagnostics/diagnosticFactory.js";
import { stripTrailingComment } from "../parser.js";
import {
    extractMacroInvocations
} from "../analysis/macroAnalysis.js";

/**
 * Validates macro declarations and invocations in a document.
 * @param {vscode.TextDocument} document - The document to validate
 * @param {Function} getRuleSeverity - Severity resolver
 * @param {Object} [options] - Optional precomputed facts
 * @returns {vscode.Diagnostic[]} - Array of macro diagnostics
 */
function validateMacros(document, getRuleSeverity, options = {}) {
    const diagnostics = [];
    
    const { macroCatalog = {}, macroCaseMap = {}, macroDuplicates = [], executionClassificationMap } = options;
    
    // Report duplicate macro declarations
    for (const duplicate of macroDuplicates) {
        // Skip the first declaration, only mark subsequent ones
        for (let i = 1; i < duplicate.lineIndexes.length; i++) {
            const lineIndex = duplicate.lineIndexes[i];
            const lineText = document.lineAt(lineIndex).text;
            const lowerLineText = lineText.toLowerCase();
            const startPos = lowerLineText.indexOf("macro");
            
            if (startPos === -1) {
                continue;
            }
            
            // Find the macro name position
            const nameMatch = lineText.substring(startPos).match(/macro\s+([A-Za-z_][A-Za-z0-9_]*)/i);
            if (!nameMatch) {
                continue;
            }
            
            const nameStart = startPos + nameMatch.index + nameMatch[0].length - nameMatch[1].length;
            const nameEnd = nameStart + nameMatch[1].length;
            
            const dupDiag = createDiagnostic(
                { start: { line: lineIndex, character: nameStart }, end: { line: lineIndex, character: nameEnd } },
                { messageId: "ACU-MAC-001", params: { macroName: duplicate.name } },
                getRuleSeverity
            );
            if (dupDiag) {
                diagnostics.push(dupDiag);
            }
        }
    }

    // Validate macro invocations
    for (let lineIndex = 0; lineIndex < document.lineCount; lineIndex += 1) {
        const rawLineText = document.lineAt(lineIndex).text;
        const lineText = stripTrailingComment(rawLineText);

        // Skip macro declaration lines
        if (/^\s*#?\s*MACRO\s+/i.test(lineText)) {
            continue;
        }

        // Skip output lines (macros typically don't expand in output)
        if (executionClassificationMap && executionClassificationMap[lineIndex].isOutput) {
            continue;
        }

        const invocations = extractMacroInvocations(lineText, macroCatalog);
        
        for (const invocation of invocations) {
            const macroEntry = macroCatalog[invocation.upperName];
            
            // Check for case mismatch
            const canonicalName = macroCaseMap[invocation.upperName];
            if (canonicalName && invocation.name !== canonicalName) {
                const caseDiag = createDiagnostic(
                    { start: { line: lineIndex, character: invocation.startPos }, end: { line: lineIndex, character: invocation.startPos + invocation.name.length } },
                    { messageId: "ACU-MAC-002", params: { usedName: invocation.name, declaredName: canonicalName } },
                    getRuleSeverity
                );
                if (caseDiag) {
                    diagnostics.push(caseDiag);
                }
            }

            // Validate parameter count
            const expectedParamCount = macroEntry.params.length;
            
            if (expectedParamCount === 0) {
                // Macro expects no parameters
                if (invocation.hasParens) {
                    const paramDiag = createDiagnostic(
                        { start: { line: lineIndex, character: invocation.startPos }, end: { line: lineIndex, character: invocation.endPos } },
                        { messageId: "ACU-MAC-003", params: { macroName: invocation.name, expectedCount: expectedParamCount, actualCount: invocation.argCount } },
                        getRuleSeverity
                    );
                    if (paramDiag) {
                        diagnostics.push(paramDiag);
                    }
                }
            } else {
                // Macro expects parameters
                if (!invocation.hasParens) {
                    const paramDiag = createDiagnostic(
                        { start: { line: lineIndex, character: invocation.startPos }, end: { line: lineIndex, character: invocation.endPos } },
                        { messageId: "ACU-MAC-004", params: { macroName: invocation.name, expectedCount: expectedParamCount } },
                        getRuleSeverity
                    );
                    if (paramDiag) {
                        diagnostics.push(paramDiag);
                    }
                } else if (invocation.argCount !== expectedParamCount) {
                    const paramDiag = createDiagnostic(
                        { start: { line: lineIndex, character: invocation.startPos }, end: { line: lineIndex, character: invocation.endPos } },
                        { messageId: "ACU-MAC-005", params: { macroName: invocation.name, expectedCount: expectedParamCount, actualCount: invocation.argCount } },
                        getRuleSeverity
                    );
                    if (paramDiag) {
                        diagnostics.push(paramDiag);
                    }
                }
            }
        }
    }

    return diagnostics;
}

export {
    validateMacros
};
