/**
 * @fileoverview Provides a utility class for extracting and parsing YAML frontmatter from markdown.
 * Supports Obsidian-style and Jekyll-style frontmatter (YAML between --- delimiters).
 * Leverages the existing yamlParser for parsing extracted YAML content.
 * @module src/utils/parsing/frontmatterParser
 */
import { McpError, validationError } from '../../types-global/errors.js';
import { logger } from '../../utils/internal/logger.js';
import { requestContextService } from '../../utils/internal/requestContext.js';
import { yamlParser } from './yamlParser.js';
/**
 * Regular expression to extract frontmatter from markdown.
 * Matches YAML content between --- delimiters at the start of the document.
 * - Group 1: YAML content between delimiters
 * - Group 2: Remaining markdown content
 * @private
 */
const frontmatterRegex = /^---\s*\n([\s\S]*?)^---\s*([\s\S]*)$/m;
/**
 * Utility class for extracting and parsing YAML frontmatter from markdown documents.
 * Supports Obsidian-style and Jekyll-style frontmatter (YAML between `---` delimiters).
 * Delegates YAML parsing to {@link yamlParser}.
 */
export class FrontmatterParser {
    /**
     * Extracts and parses YAML frontmatter from a markdown string.
     *
     * Looks for a `---`-delimited block at the very start of the document. If
     * found, the YAML inside is parsed via {@link yamlParser} and the remaining
     * markdown is returned separately. An empty `---\n---` block is accepted and
     * returns `frontmatter: {}` with `hasFrontmatter: true`. If no frontmatter
     * block is present, the original string is returned unchanged.
     *
     * @template T - The expected shape of the parsed frontmatter object. Defaults to `unknown`.
     * @param markdown - The markdown string that may contain a frontmatter block.
     * @param context - Optional {@link RequestContext} used for correlated logging.
     * @returns A {@link FrontmatterResult} with `frontmatter`, `content`, and `hasFrontmatter`.
     * @throws {McpError} With code `ValidationError` if the YAML content is present but malformed.
     * @example
     * ```typescript
     * import { frontmatterParser } from './frontmatterParser.js';
     *
     * const md = `---\ntitle: Hello\ntags: [a, b]\n---\n\n# Body`;
     * const result = await frontmatterParser.parse<{ title: string; tags: string[] }>(md);
     * // result.frontmatter → { title: 'Hello', tags: ['a', 'b'] }
     * // result.content     → '\n# Body'
     * // result.hasFrontmatter → true
     * ```
     */
    async parse(markdown, context) {
        const match = markdown.match(frontmatterRegex);
        if (!match) {
            // No frontmatter found - return original content
            const logContext = context ||
                requestContextService.createRequestContext({
                    operation: 'FrontmatterParser.noFrontmatter',
                });
            logger.debug('No frontmatter detected in markdown.', logContext);
            return {
                frontmatter: {},
                content: markdown,
                hasFrontmatter: false,
            };
        }
        const yamlContent = match[1] ?? '';
        const markdownContent = match[2] ?? '';
        const logContext = context ||
            requestContextService.createRequestContext({
                operation: 'FrontmatterParser.parse',
            });
        logger.debug('Frontmatter detected, extracting and parsing.', {
            ...logContext,
            yamlLength: yamlContent.length,
            contentLength: markdownContent.length,
        });
        // Validate that we have YAML content
        const trimmedYaml = yamlContent.trim();
        if (!trimmedYaml) {
            logger.debug('Empty frontmatter block detected.', logContext);
            return {
                frontmatter: {},
                content: markdownContent,
                hasFrontmatter: true,
            };
        }
        try {
            // Use existing yamlParser for parsing (handles <think> blocks too)
            const parsedFrontmatter = await yamlParser.parse(yamlContent, context);
            logger.debug('Frontmatter parsed successfully.', {
                ...logContext,
                frontmatterKeys: parsedFrontmatter &&
                    typeof parsedFrontmatter === 'object' &&
                    !Array.isArray(parsedFrontmatter)
                    ? Object.keys(parsedFrontmatter)
                    : [],
            });
            return {
                frontmatter: parsedFrontmatter,
                content: markdownContent,
                hasFrontmatter: true,
            };
        }
        catch (e) {
            const error = e instanceof Error ? e : new Error(String(e));
            const errorLogContext = context ||
                requestContextService.createRequestContext({
                    operation: 'FrontmatterParser.parseError',
                });
            logger.error('Failed to parse frontmatter YAML content.', {
                ...errorLogContext,
                errorDetails: error.message,
                yamlContentSample: yamlContent.substring(0, 200),
            });
            // Re-throw McpError from yamlParser or create new one
            if (error instanceof McpError) {
                throw error;
            }
            throw validationError(`Failed to parse frontmatter: ${error.message}`, {
                ...context,
                yamlContentSample: yamlContent.substring(0, 200) + (yamlContent.length > 200 ? '...' : ''),
                rawError: error instanceof Error ? error.stack : String(error),
            });
        }
    }
}
/**
 * Singleton instance of {@link FrontmatterParser}.
 *
 * Use this shared instance to extract and parse YAML frontmatter from markdown
 * documents rather than constructing a new parser per call.
 *
 * @example
 * ```typescript
 * import { frontmatterParser } from './frontmatterParser.js';
 * import { requestContextService } from '../../utils/internal/requestContext.js';
 *
 * const context = requestContextService.createRequestContext({ operation: 'ParseObsidianNote' });
 *
 * // Markdown with frontmatter
 * const markdown = `---
 * title: My Note
 * tags: [productivity, notes]
 * date: 2025-01-15
 * ---
 *
 * # Note Content
 * This is the actual note.`;
 *
 * const result = await frontmatterParser.parse(markdown, context);
 * console.log(result.frontmatter);    // { title: 'My Note', tags: [...], date: '2025-01-15' }
 * console.log(result.content);        // '\n# Note Content\nThis is the actual note.'
 * console.log(result.hasFrontmatter); // true
 *
 * // Markdown without frontmatter
 * const plainMarkdown = '# Just Content';
 * const result2 = await frontmatterParser.parse(plainMarkdown, context);
 * console.log(result2.frontmatter);    // {}
 * console.log(result2.content);        // '# Just Content'
 * console.log(result2.hasFrontmatter); // false
 * ```
 */
export const frontmatterParser = new FrontmatterParser();
//# sourceMappingURL=frontmatterParser.js.map