/**
 * Keyword capitalization validator for Acurity Architect.
 * Validates that all keywords are written in uppercase.
 * Uses the token stream so hash-mode output lines and string literals
 * are naturally excluded from the check.
 */

import { TokenType } from "../lexer/tokenTypes.js";
import { buildDocumentAst } from "../ast/documentAst.js";
import { createDiagnostic } from "../diagnostics/diagnosticFactory.js";

const INCLUDE_FAMILY = new Set(["INCLUDE", "INCLUDEONCE", "INCLUDETEST", "REQUIRE"]);

/**
 * Validates that keywords are capitalized in a document.
 * @param {object} document - The document to validate
 * @param {Function} getRuleSeverity
 * @param {object} [options]
 * @param {object[]} [options.executionClassificationMap] - Per-line execution classification
 * @returns {object[]} - Array of keyword capitalization diagnostics
 */
function validateKeywordCapitalization(document, getRuleSeverity, options = {}) {
    const diagnostics = [];
    const { tokens } = buildDocumentAst(document);
    const ecm = options.executionClassificationMap || null;

    // Track lines where we've seen an INCLUDE-family keyword — the remainder of
    // the line is a filename argument, not source code to validate.
    const includeLines = new Set();

    for (const token of tokens) {
        if (token.type !== TokenType.KEYWORD) continue;

        // Skip tokens on output or non-executable lines (e.g. #NOTE, #?? debug lines).
        if (ecm) {
            const cls = ecm[token.line];
            if (cls && (cls.isOutput || !cls.isExecutable)) continue;
        }

        // Skip tokens that follow an INCLUDE-family keyword on the same line.
        if (includeLines.has(token.line)) continue;

        // Once an INCLUDE-family keyword is seen, all remaining tokens on that line
        // form the filename argument and must not be checked for capitalisation.
        if (INCLUDE_FAMILY.has(token.value.toUpperCase())) {
            includeLines.add(token.line);
        }

        if (token.value === token.value.toUpperCase()) continue;

        const range = {
            start: { line: token.line, character: token.char },
            end:   { line: token.line, character: token.char + token.value.length }
        };
        const diagnostic = createDiagnostic(
            range,
            { messageId: "ACU-KWD-001", params: { keyword: token.value, uppercase: token.value.toUpperCase() } },
            getRuleSeverity
        );
        if (diagnostic) diagnostics.push(diagnostic);
    }

    return diagnostics;
}

export {
    validateKeywordCapitalization
};
