import { mkdir, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";

interface SnippetSource {
  readonly source: string;
  readonly outputDir: string;
  readonly language: string;
}

const sources: readonly SnippetSource[] = [
  {
    source: "examples/docs-sdk-quickstart/src/main.ts",
    outputDir: "docs/snippets/sdk/quickstart",
    language: "ts",
  },
];

const markerPattern = /^\s*\/\/ docs:(start|end) ([a-z0-9-]+)\s*$/;

const dedent = (lines: readonly string[]): string => {
  const nonBlank = lines.filter((line) => line.trim().length > 0);
  const indent = Math.min(
    ...nonBlank.map((line) => {
      const match = line.match(/^\s*/);
      return match?.[0].length ?? 0;
    }),
  );

  return lines
    .map((line) => line.slice(indent))
    .join("\n")
    .trim();
};

for (const source of sources) {
  const text = await Bun.file(source.source).text();
  const snippets = new Map<string, string[]>();
  let current: { readonly name: string; readonly lines: string[] } | null = null;

  for (const line of text.split("\n")) {
    const marker = line.match(markerPattern);
    if (marker) {
      const [, kind, name] = marker;
      if (kind === "start") {
        if (current) throw new Error(`Nested snippet marker in ${source.source}: ${name}`);
        current = { name, lines: [] };
      } else {
        if (!current || current.name !== name) {
          throw new Error(`Unmatched snippet end in ${source.source}: ${name}`);
        }
        snippets.set(name, current.lines);
        current = null;
      }
      continue;
    }

    if (current) current.lines.push(line);
  }

  if (current) throw new Error(`Unclosed snippet marker in ${source.source}: ${current.name}`);

  for (const [name, lines] of snippets) {
    const output = join(source.outputDir, `${name}.mdx`);
    await mkdir(dirname(output), { recursive: true });
    await writeFile(
      output,
      `{/_\nThis file is generated by scripts/generate-doc-snippets.ts.\nEdit ${source.source} between the docs:start/docs:end markers instead.\n_/}\n\n\`\`\`${source.language}\n${dedent(lines)}\n\`\`\`\n`,
    );
  }
}
