/**
 * LaTeX Folding Range Provider for Monaco Editor.
 * Provides code folding for LaTeX environments and sections.
 */
import type * as Monaco from 'monaco-editor';

export class LaTeXFoldingRangeProvider implements Monaco.languages.FoldingRangeProvider {
    constructor(private monaco: typeof Monaco) {}

    provideFoldingRanges(
        model: Monaco.editor.ITextModel,
        context: Monaco.languages.FoldingContext,
        token: Monaco.CancellationToken
    ): Monaco.languages.ProviderResult<Monaco.languages.FoldingRange[]> {
        const ranges: Monaco.languages.FoldingRange[] = [];
        const lineCount = model.getLineCount();

        // Stack for tracking nested environments
        const envStack: { name: string; line: number }[] = [];

        // Stack for sections (hierarchical)
        const sectionStack: { level: number; line: number }[] = [];
        const sectionLevels: Record<string, number> = {
            part: 0,
            chapter: 1,
            section: 2,
            subsection: 3,
            subsubsection: 4,
            paragraph: 5,
            subparagraph: 6,
        };

        // Multi-line comment tracking
        let commentStart: number | null = null;

        for (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {
            const line = model.getLineContent(lineNumber);

            // Check for \begin{environment}
            const beginMatch = line.match(/\\begin\{(\w+\*?)\}/);
            if (beginMatch) {
                envStack.push({ name: beginMatch[1], line: lineNumber });
            }

            // Check for \end{environment}
            const endMatch = line.match(/\\end\{(\w+\*?)\}/);
            if (endMatch && envStack.length > 0) {
                // Find matching begin
                for (let i = envStack.length - 1; i >= 0; i--) {
                    if (envStack[i].name === endMatch[1]) {
                        if (lineNumber > envStack[i].line) {
                            ranges.push({
                                start: envStack[i].line,
                                end: lineNumber,
                                kind: this.monaco.languages.FoldingRangeKind.Region,
                            });
                        }
                        envStack.splice(i, 1);
                        break;
                    }
                }
            }

            // Check for sections
            const sectionMatch = line.match(
                /\\(part|chapter|section|subsection|subsubsection|paragraph|subparagraph)\*?\s*[\[{]/
            );
            if (sectionMatch) {
                const level = sectionLevels[sectionMatch[1]];

                // Close any sections at same or higher level (lower number = higher level)
                while (
                    sectionStack.length > 0 &&
                    sectionStack[sectionStack.length - 1].level >= level
                ) {
                    const prev = sectionStack.pop()!;
                    if (lineNumber - prev.line > 1) {
                        ranges.push({
                            start: prev.line,
                            end: lineNumber - 1,
                            kind: this.monaco.languages.FoldingRangeKind.Region,
                        });
                    }
                }

                sectionStack.push({ level, line: lineNumber });
            }

            // Check for comment blocks (consecutive comment lines)
            const isComment = line.trim().startsWith('%');
            if (isComment && commentStart === null) {
                commentStart = lineNumber;
            } else if (!isComment && commentStart !== null) {
                if (lineNumber - commentStart > 2) {
                    ranges.push({
                        start: commentStart,
                        end: lineNumber - 1,
                        kind: this.monaco.languages.FoldingRangeKind.Comment,
                    });
                }
                commentStart = null;
            }
        }

        // Close remaining sections at end of document
        while (sectionStack.length > 0) {
            const prev = sectionStack.pop()!;
            if (lineCount - prev.line > 1) {
                ranges.push({
                    start: prev.line,
                    end: lineCount,
                    kind: this.monaco.languages.FoldingRangeKind.Region,
                });
            }
        }

        // Close any unclosed comment block
        if (commentStart !== null && lineCount - commentStart > 2) {
            ranges.push({
                start: commentStart,
                end: lineCount,
                kind: this.monaco.languages.FoldingRangeKind.Comment,
            });
        }

        return ranges;
    }
}

/**
 * Creates a folding range provider for LaTeX.
 */
export function createFoldingProvider(monaco: typeof Monaco): LaTeXFoldingRangeProvider {
    return new LaTeXFoldingRangeProvider(monaco);
}
