import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import yaml from 'js-yaml';
import { createJiti } from 'jiti';
import { visit } from 'unist-util-visit';
import createMDX from '@next/mdx';
import remarkFrontmatter from 'remark-frontmatter';
import remarkGfm from 'remark-gfm';
import { remarkMermaid } from '@theguild/remark-mermaid';
import rehypeMdxImportMedia from 'rehype-mdx-import-media';

// src/withMarkdownWebBook.ts
var metaPageLoaderPath = fileURLToPath(
  new URL("./meta-page-loader.cjs", import.meta.url)
);
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function markdownLinkSyntaxToHtmlLinkSyntax(string) {
  return string.replace(/\[([^\]]+)\]\(([^\)]+)\)/g, "$2");
}
function loadAbbreviations(localePath) {
  const base = process.cwd();
  const dir = localePath ? path.join(base, "pages", localePath) : base;
  const raw = {};
  try {
    const content = yaml.load(
      fs.readFileSync(path.join(dir, "abbreviations.yaml"), "utf8")
    );
    if (content && typeof content === "object") {
      Object.assign(raw, content);
    }
  } catch {
  }
  if (!localePath) {
    try {
      const abkuerzungen = yaml.load(
        fs.readFileSync(path.join(base, "abkuerzungen.yaml"), "utf8")
      );
      if (abkuerzungen && typeof abkuerzungen === "object") {
        for (const [key, value] of Object.entries(abkuerzungen)) {
          if (!(key in raw)) raw[key] = { value: String(value) };
        }
      }
    } catch {
    }
    try {
      const glossar = yaml.load(
        fs.readFileSync(path.join(base, "glossar.yaml"), "utf8")
      );
      if (glossar && typeof glossar === "object") {
        for (const [key, value] of Object.entries(glossar)) {
          if (!(key in raw)) raw[key] = { value: String(value) };
        }
      }
    } catch {
    }
  }
  const termMap = {};
  const variantToCanonical = {};
  for (const [term, entry] of Object.entries(raw)) {
    const e = typeof entry === "string" ? { value: entry } : entry;
    const valueStr = markdownLinkSyntaxToHtmlLinkSyntax(e.value);
    termMap[term] = valueStr;
    variantToCanonical[term] = term;
    for (const variant of e.variants ?? []) {
      termMap[variant] = valueStr;
      variantToCanonical[variant] = term;
    }
  }
  return { termMap, variantToCanonical };
}
function detectLocaleFromPath(filePath, locales) {
  if (!filePath || locales.length === 0) return void 0;
  const parts = filePath.replace(/\\/g, "/").split("/");
  const pagesIdx = parts.lastIndexOf("pages");
  if (pagesIdx < 0) return void 0;
  const candidate = parts[pagesIdx + 1];
  return candidate && locales.includes(candidate) ? candidate : void 0;
}
var remarkAbbrev = function(options) {
  return (ast, file) => {
    const locales = options?.locales ?? [];
    const locale = detectLocaleFromPath(file?.path, locales);
    const { termMap, variantToCanonical } = loadAbbreviations(locale);
    if (Object.keys(termMap).length === 0) return ast;
    const acronymsRegExp = new RegExp(
      "\\b(" + Object.keys(termMap).map(escapeRegExp).join("|") + ")\\b",
      "g"
    );
    const visitForAbbreviations = ["paragraph", "strong", "emphasis"];
    for (const nodeType of visitForAbbreviations) {
      visit(ast, nodeType, function(node) {
        node.children = node.children.map(function(child) {
          if (child.type === "text") {
            const newChildren = child.value.split(acronymsRegExp).map(function(part) {
              if (termMap[part]) {
                return {
                  type: "abbr",
                  data: {
                    hName: "abbr",
                    hChildren: [{ type: "text", value: part }],
                    hProperties: {
                      title: termMap[part],
                      "data-canonical": variantToCanonical[part]
                    }
                  }
                };
              } else {
                return { type: "text", value: part };
              }
            });
            return newChildren;
          }
          return [child];
        }).flat();
      });
    }
    return ast;
  };
};
var withMarkdownWebBook = (config) => {
  const locales = [...config.i18n?.locales ?? []];
  const defaultLocale = config.i18n?.defaultLocale;
  const withMDX = createMDX({
    extension: /\.mdx?$/,
    options: {
      remarkPlugins: [
        remarkFrontmatter,
        remarkGfm,
        remarkMermaid,
        [remarkAbbrev, { locales }]
      ],
      rehypePlugins: [rehypeMdxImportMedia]
    }
  });
  buildFiles(locales);
  const mdxConfig = withMDX({
    ...config,
    i18n: void 0,
    env: {
      ...config.env,
      ...locales.length > 0 && { DWT_LOCALES: JSON.stringify(locales) },
      ...defaultLocale && { DWT_DEFAULT_LOCALE: defaultLocale }
    },
    pageExtensions: [
      ...config.pageExtensions ?? ["js", "jsx", "ts", "tsx"],
      "md",
      "mdx"
    ],
    webpack(webpackConfig, options) {
      webpackConfig.module.rules.push({
        test: /_meta\.[jt]sx?$/,
        use: [metaPageLoaderPath]
      });
      if (typeof config.webpack === "function") {
        return config.webpack(webpackConfig, options);
      }
      return webpackConfig;
    }
  });
  return mdxConfig;
};
var buildFiles = (locales) => {
  let dir;
  if (!fs.existsSync("pages")) {
    dir = process.cwd() + "/src/pages";
  } else {
    dir = process.cwd() + "/pages";
  }
  if (locales.length <= 1) {
    const { termMap, variantToCanonical } = loadAbbreviations(void 0);
    const glossaryEntries = {};
    for (const [term, canonical] of Object.entries(variantToCanonical)) {
      if (term === canonical) glossaryEntries[term] = termMap[term];
    }
    console.log("Writing glossary.ts to the file system");
    fs.writeFileSync(
      path.join(process.cwd(), "glossary.ts"),
      `export const glossary = ${JSON.stringify(glossaryEntries, null, 2)};
`
    );
  } else {
    for (const locale of locales) {
      const { termMap, variantToCanonical } = loadAbbreviations(locale);
      const glossaryEntries = {};
      for (const [term, canonical] of Object.entries(variantToCanonical)) {
        if (term === canonical) glossaryEntries[term] = termMap[term];
      }
      const fileName = `glossary-${locale}.ts`;
      console.log(`Writing ${fileName} to the file system`);
      fs.writeFileSync(
        path.join(process.cwd(), fileName),
        `export const glossary = ${JSON.stringify(glossaryEntries, null, 2)};
`
      );
    }
  }
  const pageMap = buildPageMap(dir, dir);
  console.log("Writing pageMap.ts to the file system");
  fs.writeFileSync(
    path.join(process.cwd(), "pageMap.ts"),
    `import type { PageMapItem } from "@document-writing-tools/kernux-theme";

export const pageMap: PageMapItem[] = ${JSON.stringify(pageMap, null, 2)};
`
  );
  const searchData = buildSearchData(dir, dir, locales);
  const publicDir = path.join(process.cwd(), "public");
  fs.mkdirSync(publicDir, { recursive: true });
  if (locales.length <= 1) {
    console.log("Writing public/search-data.json to the file system");
    fs.writeFileSync(
      path.join(publicDir, "search-data.json"),
      JSON.stringify(searchData)
    );
  } else {
    for (const locale of locales) {
      const localeData = Object.fromEntries(
        Object.entries(searchData).filter(
          ([, v]) => !v.locale || v.locale === locale
        )
      );
      console.log(
        `Writing public/search-data-${locale}.json to the file system`
      );
      fs.writeFileSync(
        path.join(publicDir, `search-data-${locale}.json`),
        JSON.stringify(localeData)
      );
    }
  }
};
function resolveLocale(route, locales, frontMatterLang) {
  if (frontMatterLang) return frontMatterLang;
  if (locales.length === 0) return void 0;
  const first = route.split("/").filter(Boolean)[0];
  return first && locales.includes(first) ? first : void 0;
}
function buildSearchData(dir, rootDir, locales) {
  const entries = fs.readdirSync(dir, { withFileTypes: true, recursive: true });
  const result = {};
  for (const entry of entries) {
    if (entry.isDirectory()) continue;
    if (!entry.name.endsWith(".mdx") && !entry.name.endsWith(".md")) continue;
    if (entry.name.startsWith("_")) continue;
    const fullPath = path.join(entry.parentPath, entry.name);
    const route = "/" + path.relative(rootDir, fullPath).replace(/\\/g, "/").replace(/\.mdx?$/, "").replace(/\/index$/, "").replace(/^index$/, "");
    const frontMatter = readFrontMatter(fullPath);
    const title = frontMatter.title ?? entry.name.replace(/\.mdx?$/, "");
    const locale = resolveLocale(
      route,
      locales,
      frontMatter.lang
    );
    const contents = fs.readFileSync(fullPath, "utf8");
    const body = contents.replace(/^---[\s\S]*?---\s*/m, "");
    const data = {};
    const headingRegex = /^(#{1,6})\s+(.+?)(?:\s*\{[^}]*\})?\s*$/gm;
    let currentKey = "";
    let lastIndex = 0;
    let match;
    while ((match = headingRegex.exec(body)) !== null) {
      const prose = body.slice(lastIndex, match.index).trim();
      if (prose) {
        data[currentKey] = (data[currentKey] ? data[currentKey] + "\n" : "") + prose;
      }
      const value = match[2].trim();
      const id = value.toLowerCase().replace(/\s+/g, "-").replace(/[^\w-]/g, "");
      currentKey = `${id}#${value}`;
      lastIndex = headingRegex.lastIndex;
    }
    const trailing = body.slice(lastIndex).trim();
    if (trailing) {
      data[currentKey] = (data[currentKey] ? data[currentKey] + "\n" : "") + trailing;
    }
    if (Object.keys(data).length === 0 && !trailing) continue;
    result[route] = { title, ...locale ? { locale } : {}, data };
  }
  return result;
}
function readFrontMatter(filePath) {
  try {
    const contents = fs.readFileSync(filePath, "utf8");
    const match = contents.match(/^---\s*([\s\S]*?)\s*---/m);
    if (!match) return {};
    return yaml.load(match[1]) ?? {};
  } catch {
    return {};
  }
}
function extractHeadings(filePath) {
  try {
    const contents = fs.readFileSync(filePath, "utf8");
    const body = contents.replace(/^---[\s\S]*?---\s*/m, "");
    const headings = [];
    const headingRegex = /^(#{2,6})\s+(.+?)(?:\s*\{[^}]*\})?\s*$/gm;
    let match;
    while ((match = headingRegex.exec(body)) !== null) {
      const depth = match[1].length;
      const value = match[2].trim();
      const id = value.toLowerCase().replace(/\s+/g, "-").replace(/[^\w-]/g, "");
      headings.push({ depth, value, id });
    }
    return headings;
  } catch {
    return [];
  }
}
var jiti = createJiti(import.meta.url);
function readMetaFile(dir) {
  const tsPath = path.join(dir, "_meta.ts");
  const jsonPath = path.join(dir, "_meta.json");
  if (fs.existsSync(tsPath)) {
    try {
      const content = fs.readFileSync(tsPath, "utf8");
      const mod = jiti.evalModule(content, { filename: tsPath });
      return ("default" in mod ? mod.default : mod) ?? null;
    } catch {
      return null;
    }
  }
  if (fs.existsSync(jsonPath)) {
    try {
      return JSON.parse(fs.readFileSync(jsonPath, "utf8"));
    } catch {
      return null;
    }
  }
  return null;
}
function normalizeMeta(raw) {
  return Object.fromEntries(
    Object.entries(raw).map(([k, v]) => [
      k,
      typeof v === "string" ? { title: v } : v
    ])
  );
}
function buildPageMap(dir, rootDir) {
  const entries = fs.readdirSync(dir, { withFileTypes: true });
  const rawMetaFile = readMetaFile(dir);
  const hasMeta = rawMetaFile !== null;
  const meta = normalizeMeta(rawMetaFile ?? {});
  const fallback = meta["*"] ?? {};
  const metaKeys = Object.keys(meta).filter((k) => k !== "*");
  const metaKeyOrder = new Map(metaKeys.map((k, i) => [k, i]));
  const fileNodes = /* @__PURE__ */ new Map();
  const folderNodes = [];
  for (const entry of entries) {
    if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
    const fullPath = path.join(dir, entry.name);
    const route = "/" + path.relative(rootDir, fullPath).replace(/\\/g, "/").replace(/\.mdx?$/, "").replace(/\/index$/, "").replace(/^index$/, "");
    if (entry.isDirectory()) {
      folderNodes.push({
        kind: "folder",
        name: entry.name,
        route: route || "/",
        children: buildPageMap(fullPath, rootDir),
        meta: meta[entry.name] ?? fallback
      });
    } else if (entry.name.endsWith(".mdx") || entry.name.endsWith(".md")) {
      const name = entry.name.replace(/\.mdx?$/, "");
      fileNodes.set(name, {
        kind: "file",
        name,
        route: route || "/",
        filePath: path.relative(rootDir, fullPath).replace(/\\/g, "/"),
        frontMatter: readFrontMatter(fullPath),
        toc: extractHeadings(fullPath),
        meta: meta[name] ?? fallback
      });
    }
  }
  const nodes = [];
  for (const folder of folderNodes) {
    const indexPage = fileNodes.get(folder.name);
    if (indexPage) fileNodes.delete(folder.name);
    nodes.push(indexPage ? { ...folder, indexPage } : folder);
  }
  nodes.push(...fileNodes.values());
  const existingNames = new Set(nodes.map((n) => n.name));
  for (const key of metaKeys) {
    if (existingNames.has(key)) continue;
    const entry = meta[key];
    if (entry.type === "separator" || entry.href || entry.type === "menu") {
      nodes.push({
        kind: "separator",
        name: key,
        meta: entry
      });
    } else {
      throw new Error(
        `_meta key "${key}" in ${dir} refers to a page that cannot be found. Remove it or add an href.`
      );
    }
  }
  if (hasMeta) {
    const listed = nodes.filter((n) => metaKeyOrder.has(n.name)).sort((a, b) => metaKeyOrder.get(a.name) - metaKeyOrder.get(b.name));
    const unlisted = nodes.filter((n) => !metaKeyOrder.has(n.name)).map((n) => ({ ...n, meta: { ...n.meta, display: "hidden" } }));
    return [...listed, ...unlisted];
  }
  return nodes.sort((a, b) => a.name < b.name ? -1 : 1);
}

export { remarkAbbrev, withMarkdownWebBook };
//# sourceMappingURL=withMarkdownWebBook.js.map
//# sourceMappingURL=withMarkdownWebBook.js.map