/* eslint-disable regexp/optimal-quantifier-concatenation, regexp/no-misleading-capturing-group, regexp/no-super-linear-backtracking */
import fs from 'node:fs/promises';
import path from 'node:path';
import { isProduction } from '@rspress/shared';
import { logger } from 'rspress/core';
import { parse, stringify } from 'yaml';
import { cyan, red } from 'yoctocolors';
import { normalizeImgSrc } from './normalize-img-src.js';
import { resolveReference } from './resolve-reference.js';
import { resolveRelease } from './resolve-release.js';
import { getFrontmatterNode, isCI, mdProcessor, mdxProcessor } from './utils.js';
const MD_REF_START_COMMENT_PATTERN = /<!-{2,} *reference-start#(.+) *-{2,}>/;
const MDX_REF_START_COMMENT_PATTERN = /\{\/\*+ *reference-start#(.+) *\*+\/\}/;
const MDX_REF_START_PATTERN = /\/\*+ *reference-start#(.+) *\*+\//;
const MD_REF_END_COMMENT_PATTERN = /<!-{2,} *reference-end *-{2,}>/;
const MDX_REF_END_PATTERN = /\/\*+ *reference-end *\*+\//;
export const MD_RELEASE_COMMENT_PATTERN = /<!-{2,} *release-notes-for-bugs\?(.+) *-{2,}>/;
export const MDX_RELEASE_COMMENT_PATTERN = /\{\/\*+ *release-notes-for-bugs\?(.+) *\*+\/\}/;
const MDX_RELEASE_PATTERN = /\/\*+ *release-notes-for-bugs\?(.+) *\*+\//;
export const maybeHaveRef = (filepath, content) => {
    if (!/\.mdx?$/.test(filepath)) {
        return;
    }
    return (filepath.endsWith('.mdx')
        ? [MDX_REF_START_COMMENT_PATTERN, MDX_RELEASE_COMMENT_PATTERN]
        : [MD_REF_START_COMMENT_PATTERN, MD_RELEASE_COMMENT_PATTERN]).some((p) => p.test(content));
};
export const remarkReplace = function ({ lang, localBasePath, root, items, force, releaseNotes }) {
    return async (ast, vfile) => {
        const filepath = vfile.path;
        let content = vfile.toString();
        if (!maybeHaveRef(filepath, content)) {
            return;
        }
        const localPublicBase = path.resolve(root, 'public');
        const targetBase = path.dirname(filepath);
        const isMdx = filepath.endsWith('.mdx');
        const processor = isMdx ? mdxProcessor : mdProcessor;
        const originalAst = vfile.data.original
            ? ast
            : processor.parse((content = await fs.readFile(filepath, 'utf8')));
        const frontmatterNode = getFrontmatterNode(originalAst);
        let frontmatter = frontmatterNode &&
            parse(frontmatterNode.value);
        const newContentChildren = [];
        let start = false;
        let refName = '';
        let matched;
        let checkContent = false;
        const relativePath = path.relative(root, filepath);
        for (const node of originalAst.children) {
            if (node.type !== (isMdx ? 'mdxFlowExpression' : 'html')) {
                if (node.type === 'yaml') {
                    continue;
                }
                if (!start) {
                    newContentChildren.push(node);
                }
                continue;
            }
            if ((matched = node.value.match(isMdx ? MDX_REF_START_PATTERN : MD_REF_START_COMMENT_PATTERN))) {
                if (start) {
                    logger.warn(`Invalid reference start block ${red(node.value)}, nested reference blocks are not allowed`);
                }
                else {
                    checkContent = true;
                    start = true;
                    refName = matched[1].trim();
                }
                newContentChildren.push(node);
                continue;
            }
            if ((isMdx ? MDX_REF_END_PATTERN : MD_REF_END_COMMENT_PATTERN).test(node.value)) {
                if (start) {
                    start = false;
                }
                else {
                    logger.warn(`Invalid reference end block ${red(node.value)}, no matching start block found`);
                }
                const resolved = await resolveReference(localBasePath, localPublicBase, items, refName, force);
                if (resolved) {
                    const refSource = items[refName];
                    const { frontmatterMode } = refSource;
                    for (const nodeItem of resolved.contents) {
                        if (nodeItem.type !== 'yaml') {
                            newContentChildren.push(normalizeImgSrc(nodeItem, {
                                refSource,
                                localPublicBase,
                                targetBase,
                                publicBase: resolved.publicBase,
                                sourceBase: resolved.sourceBase,
                                force,
                            }));
                            continue;
                        }
                        if (!frontmatterMode || frontmatterMode === 'ignore') {
                            continue;
                        }
                        if (frontmatterMode === 'remove') {
                            frontmatter = null;
                            continue;
                        }
                        const data = parse(nodeItem.value);
                        if (frontmatterMode === 'merge') {
                            if (data) {
                                frontmatter = {
                                    ...frontmatter,
                                    ...data,
                                };
                            }
                            // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
                        }
                        else if (frontmatterMode === 'replace') {
                            frontmatter = data;
                        }
                    }
                }
                newContentChildren.push(node);
                continue;
            }
            if (!start) {
                newContentChildren.push(node);
            }
        }
        if (start) {
            logger.warn(`Invalid reference start block ${red(refName)}, no matching end block found, adding for you`);
            newContentChildren.push({
                type: isMdx ? 'mdxFlowExpression' : 'html',
                value: isMdx ? '/* reference-end */' : '<!-- reference-end -->',
            });
        }
        if (frontmatter) {
            newContentChildren.unshift({
                type: 'yaml',
                value: stringify(frontmatter).trim(),
            });
        }
        if (checkContent) {
            const newContent = processor.stringify({
                ...ast,
                children: newContentChildren.flat(),
            });
            if (content !== newContent) {
                await fs.writeFile(filepath, newContent);
                if (!vfile.data.original && isProduction()) {
                    const message = `Reference block in \`${cyan(relativePath)}\` has been updated, please commit the changes`;
                    if (isCI) {
                        process.env.__DOOM_REBUILD__ = 'true';
                    }
                    logger.warn(message);
                }
                return;
            }
        }
        const newAstChildren = [];
        const currLang = lang === null ? 'zh' : relativePath.split(/[\\/]/)[0];
        for (const node of ast.children) {
            if (node.type !== (isMdx ? 'mdxFlowExpression' : 'html')) {
                newAstChildren.push(node);
                continue;
            }
            if ((matched = node.value.match(isMdx ? MDX_RELEASE_PATTERN : MD_RELEASE_COMMENT_PATTERN))) {
                const releaseContent = await resolveRelease(releaseNotes?.queryTemplates ?? {}, matched[1].trim(), currLang, isMdx);
                newAstChildren.push(releaseContent ?? node);
                continue;
            }
            newAstChildren.push(node);
        }
        ast.children = newAstChildren.flat();
    };
};
