/**
 * EOL-required statement validator for Acurity Architect.
 * Flags unexpected tokens that appear after statements that must end the line.
 *
 * - ACU-SYN-008: Unexpected tokens after {keyword} statement — expected end of line.
 *
 * Currently enforced:
 *   VAR — after `VAR name(s) : TYPE`, no further code is permitted on the same line.
 *
 * Design:
 *   - Token-stream scan using buildDocumentAst.
 *   - For VAR: locate COLON then TYPE_KEYWORD; flag the first meaningful token that
 *     follows on the same line.
 *   - COMMENT and WHITESPACE tokens are not considered meaningful for this check.
 */

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

/**
 * Validates that VAR declarations are not followed by extra tokens on the same line.
 *
 * @param {object} document - VS Code TextDocument or PlainTextDocument
 * @param {Function} getRuleSeverity - (ruleId: string) => DiagnosticSeverity|null
 * @param {object} [options]
 * @param {object[]} [options.executionClassificationMap]
 * @returns {object[]}
 */
function validateEolRequired(document, getRuleSeverity, options = {}) {
    const diagnostics = [];
    const ecm = options.executionClassificationMap || null;

    // Early exit if rule is disabled.
    if (getRuleSeverity("unexpectedTokensAfterStatement") === null) return diagnostics;

    const { tokens } = buildDocumentAst(document);

    for (let i = 0; i < tokens.length; i++) {
        const token = tokens[i];
        if (token.type !== TokenType.KEYWORD || token.value.toUpperCase() !== "VAR") continue;

        // Skip output or non-executable lines.
        if (ecm) {
            const cls = ecm[token.line];
            if (cls && (cls.isOutput || !cls.isExecutable)) continue;
        }

        const lineIndex = token.line;

        // Advance past variable name(s) to find the COLON.
        let j = i + 1;
        while (j < tokens.length && tokens[j].line === lineIndex &&
               tokens[j].type !== TokenType.COLON) {
            j++;
        }
        if (j >= tokens.length || tokens[j].line !== lineIndex) continue;

        // Advance past the COLON and any whitespace to find the TYPE_KEYWORD.
        j++;
        while (j < tokens.length && tokens[j].line === lineIndex &&
               tokens[j].type === TokenType.WHITESPACE) {
            j++;
        }
        if (j >= tokens.length || tokens[j].line !== lineIndex) continue;
        if (tokens[j].type !== TokenType.TYPE_KEYWORD) continue;

        // TYPE_KEYWORD found. Advance past any trailing whitespace and comments.
        j++;
        while (j < tokens.length && tokens[j].line === lineIndex &&
               (tokens[j].type === TokenType.WHITESPACE ||
                tokens[j].type === TokenType.COMMENT)) {
            j++;
        }

        // If a meaningful token remains on the same line, it is unexpected.
        if (j < tokens.length &&
            tokens[j].line === lineIndex &&
            tokens[j].type !== TokenType.NEWLINE &&
            tokens[j].type !== TokenType.EOF) {
            const extra = tokens[j];
            const range = {
                start: { line: lineIndex, character: extra.char },
                end:   { line: lineIndex, character: extra.char + extra.value.length }
            };
            const diag = createDiagnostic(
                range,
                { messageId: "ACU-SYN-008", params: { keyword: "VAR" } },
                getRuleSeverity
            );
            if (diag) diagnostics.push(diag);
        }
    }

    return diagnostics;
}

export { validateEolRequired };
