import { createDiagnostic } from "../diagnostics/diagnosticFactory.js";
import { getRobodocConfig, getExpectedRobodocHeader, getBaseFilename } from "../robodoc/robodocUtils.js";

const DOC_START_PATTERN = /^\s*\/\/\s*@docStart\*([a-z])\*\s+(.+?)\s*$/i;
const DOC_END_PATTERN = /^\s*\/\/\s*@docEnd\b/i;

function escapeRegex(text) {
    return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

function normalizeSections(requiredSections) {
    if (!Array.isArray(requiredSections)) {
        return [];
    }

    return requiredSections
        .map((section) => String(section || "").trim())
        .filter((section) => section.length > 0);
}

function buildLineRange(lineIndex, lineText, token) {
    const tokenIndex = token ? lineText.indexOf(token) : -1;
    if (tokenIndex >= 0) {
        return { start: { line: lineIndex, character: tokenIndex }, end: { line: lineIndex, character: tokenIndex + token.length } };
    }

    const firstNonWhitespace = lineText.search(/\S/);
    const start = firstNonWhitespace >= 0 ? firstNonWhitespace : 0;
    return { start: { line: lineIndex, character: start }, end: { line: lineIndex, character: lineText.length } };
}

function validateRobodoc(document, getRuleSeverity, options = {}) {
    const diagnostics = [];
    const { robodocConfig } = options;
    const config = { ...getRobodocConfig(), ...(robodocConfig || {}) };
    
    if (!config.enabled) {
        return diagnostics;
    }

    let docStart = null;
    let docEnd = null;

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

        if (!docStart) {
            const startMatch = lineText.match(DOC_START_PATTERN);
            if (startMatch) {
                docStart = {
                    lineIndex,
                    lineText,
                    kindChar: startMatch[1].toLowerCase(),
                    target: startMatch[2].trim()
                };
            }
        }

        if (!docEnd && DOC_END_PATTERN.test(lineText)) {
            docEnd = { lineIndex, lineText };
        }
    }

    if (config.requireDocBlock && !docStart) {
        const firstLineText = document.lineAt(0).text;
        const missingStartDiagnostic = createDiagnostic(
            buildLineRange(0, firstLineText, null),
            { messageId: "ACU-RBD-001", params: {} },
            getRuleSeverity
        );
        if (missingStartDiagnostic) {
            diagnostics.push(missingStartDiagnostic);
        }
        return diagnostics;
    }

    if (!docStart) {
        return diagnostics;
    }

    if (!docEnd || docEnd.lineIndex < docStart.lineIndex) {
        const missingEndDiagnostic = createDiagnostic(
            buildLineRange(docStart.lineIndex, docStart.lineText, "@docStart"),
            { messageId: "ACU-RBD-002", params: {} },
            getRuleSeverity
        );
        if (missingEndDiagnostic) {
            diagnostics.push(missingEndDiagnostic);
        }
        return diagnostics;
    }

    const filename = getBaseFilename(document);
    const expectedHeader = getExpectedRobodocHeader(filename, config);

    if (docStart.kindChar !== expectedHeader.kindChar) {
        const headerKindDiagnostic = createDiagnostic(
            buildLineRange(docStart.lineIndex, docStart.lineText, `*${docStart.kindChar}*`),
            {
                messageId: "ACU-RBD-003",
                params: {
                    expectedKind: expectedHeader.kind.toUpperCase(),
                    expectedTag: `*${expectedHeader.kindChar}*`,
                    actualTag: `*${docStart.kindChar}*`
                }
            },
            getRuleSeverity
        );
        if (headerKindDiagnostic) {
            diagnostics.push(headerKindDiagnostic);
        }
    }

    if (config.validateHeaderTarget && docStart.target.toUpperCase() !== expectedHeader.target.toUpperCase()) {
        const headerTargetDiagnostic = createDiagnostic(
            buildLineRange(docStart.lineIndex, docStart.lineText, docStart.target),
            {
                messageId: "ACU-RBD-004",
                params: {
                    expectedTarget: expectedHeader.target,
                    actualTarget: docStart.target
                }
            },
            getRuleSeverity
        );
        if (headerTargetDiagnostic) {
            diagnostics.push(headerTargetDiagnostic);
        }
    }

    const requiredSections = normalizeSections(config.requiredSections);
    for (const sectionName of requiredSections) {
        const sectionPattern = new RegExp(`^\\s*//\\s*${escapeRegex(sectionName)}\\b`, "i");
        let found = false;

        for (let lineIndex = docStart.lineIndex + 1; lineIndex < docEnd.lineIndex; lineIndex += 1) {
            if (sectionPattern.test(document.lineAt(lineIndex).text)) {
                found = true;
                break;
            }
        }

        if (!found) {
            const missingSectionDiagnostic = createDiagnostic(
                buildLineRange(docStart.lineIndex, docStart.lineText, "@docStart"),
                { messageId: "ACU-RBD-005", params: { sectionName } },
                getRuleSeverity
            );
            if (missingSectionDiagnostic) {
                diagnostics.push(missingSectionDiagnostic);
            }
        }
    }

    return diagnostics;
}

export {
    validateRobodoc
};
