/**
 * Include and REQUIRE statement validators for Acurity Architect.
 *
 * Converts include-resolver findings into diagnostics:
 *   ACU-INC-001  Circular INCLUDE dependency
 *   ACU-INC-002  INCLUDE filename case mismatch
 *   ACU-INC-003  INCLUDE file not found
 *   ACU-INC-004  REQUIRE file not found
 */

import * as path from "path";
import * as fs from "fs";
import { buildTokenRange, parseRequire } from "../parser.js";
import {
    findCircularIncludeDirectives,
    findIncludeFilenameCaseMismatches,
    findMissingIncludeDirectives
} from "../includeResolver.js";
import { isPathWithinRoot } from "../includeResolver/graph.js";
import { createDiagnostic } from "../diagnostics/diagnosticFactory.js";

/**
 * @param {vscode.TextDocument} document
 * @param {Function} getRuleSeverity
 * @returns {vscode.Diagnostic[]}
 */
function validateIncludes(document, getRuleSeverity, options = {}) {
    const diagnostics = [];

    const circularIncludeDirectives = findCircularIncludeDirectives(document);
    const includeFilenameCaseMismatches = findIncludeFilenameCaseMismatches(document);
    const missingIncludeDirectives = findMissingIncludeDirectives(document);

    circularIncludeDirectives.forEach(({ lineIndex, includeFilename }) => {
        const lineText = document.lineAt(lineIndex).text;
        const diag = createDiagnostic(
            buildTokenRange(lineText, lineIndex, includeFilename, 0),
            { messageId: "ACU-INC-001", params: { includeFilename } },
            getRuleSeverity
        );
        if (diag) diagnostics.push(diag);
    });

    includeFilenameCaseMismatches.forEach(({ lineIndex, includeFilename, actualFilename }) => {
        const lineText = document.lineAt(lineIndex).text;
        const diag = createDiagnostic(
            buildTokenRange(lineText, lineIndex, includeFilename, 0),
            { messageId: "ACU-INC-002", params: { includeFilename, actualFilename } },
            getRuleSeverity
        );
        if (diag) diagnostics.push(diag);
    });

    missingIncludeDirectives.forEach(({ lineIndex, includeFilename }) => {
        const lineText = document.lineAt(lineIndex).text;
        const diag = createDiagnostic(
            buildTokenRange(lineText, lineIndex, includeFilename, 0),
            { messageId: "ACU-INC-003", params: { filename: includeFilename } },
            getRuleSeverity
        );
        if (diag) diagnostics.push(diag);
    });

    return diagnostics;
}

/**
 * Validates REQUIRE statements in a document.
 * @param {object} document - VS Code TextDocument or PlainTextDocument
 * @param {Function} getRuleSeverity - Function to get rule severity
 * @param {Object} options
 * @param {string|null} [options.workspaceRoot]
 * @returns {object[]}
 */
function validateRequire(document, getRuleSeverity, options = {}) {
    const diagnostics = [];
    const documentDir = path.dirname(document.uri.fsPath);
    const workspaceRoot = options.workspaceRoot || null;

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

        if (!requireStmt) {
            continue;
        }

        const { filename } = requireStmt;

        if (path.isAbsolute(filename)) {
            continue;
        }

        const resolvedPath = path.resolve(documentDir, filename);

        if (workspaceRoot && !isPathWithinRoot(resolvedPath, workspaceRoot)) {
            continue;
        }

        if (!fs.existsSync(resolvedPath)) {
            const diag = createDiagnostic(
                buildTokenRange(lineText, lineIndex, filename, 0),
                { messageId: "ACU-INC-004", params: { filename } },
                getRuleSeverity
            );
            if (diag) {
                diagnostics.push(diag);
            }
        }
    }

    return diagnostics;
}

export { validateIncludes, validateRequire };
