/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 */

// To do: Make this ESM.
// To do: properly check heading numbers (headings with the same text get
// numbered, this script doesn’t check that).

const assert = require('assert');
const fs = require('fs');
const GithubSlugger = require('github-slugger');
const walk = require('./walk');

let modules;

function stripLinks(line) {
  return line.replace(/\[([^\]]+)\]\([^)]+\)/, (match, p1) => p1);
}

function addHeaderID(line, slugger) {
  // check if we're a header at all
  if (!line.startsWith('#')) {
    return line;
  }

  const match =
    /^(#+\s+)(.+?)(\s*\{(?:\/\*|#)([^\}\*\/]+)(?:\*\/)?\}\s*)?$/.exec(line);
  const before = match[1] + match[2];
  const proc = modules
    .unified()
    .use(modules.remarkParse)
    .use(modules.remarkSlug);
  const tree = proc.runSync(proc.parse(before));
  const head = tree.children[0];
  assert(
    head && head.type === 'heading',
    'expected `' +
      before +
      '` to be a heading, is it using a normal space after `#`?'
  );
  const autoId = head.data.id;
  const existingId = match[4];
  const id = existingId || autoId;
  // Ignore numbers:
  const cleanExisting = existingId
    ? existingId.replace(/-\d+$/, '')
    : undefined;
  const cleanAuto = autoId.replace(/-\d+$/, '');

  if (cleanExisting && cleanExisting !== cleanAuto) {
    console.log(
      'Note: heading `%s` has a different ID (`%s`) than what GH generates for it: `%s`:',
      before,
      existingId,
      autoId
    );
  }

  return match[1] + match[2] + ' {/*' + id + '*/}';
}

function addHeaderIDs(lines) {
  // Sluggers should be per file
  const slugger = new GithubSlugger();
  let inCode = false;
  const results = [];
  lines.forEach((line) => {
    // Ignore code blocks
    if (line.startsWith('```')) {
      inCode = !inCode;
      results.push(line);
      return;
    }
    if (inCode) {
      results.push(line);
      return;
    }

    results.push(addHeaderID(line, slugger));
  });
  return results;
}

async function main(paths) {
  paths = paths.length === 0 ? ['src/content'] : paths;

  const [unifiedMod, remarkParseMod, remarkSlugMod] = await Promise.all([
    import('unified'),
    import('remark-parse'),
    import('remark-slug'),
  ]);
  const unified = unifiedMod.unified;
  const remarkParse = remarkParseMod.default;
  const remarkSlug = remarkSlugMod.default;
  modules = {unified, remarkParse, remarkSlug};
  const files = paths.map((path) => [...walk(path)]).flat();

  files.forEach((file) => {
    if (!(file.endsWith('.md') || file.endsWith('.mdx'))) {
      return;
    }

    const content = fs.readFileSync(file, 'utf8');
    const lines = content.split('\n');
    const updatedLines = addHeaderIDs(lines);
    fs.writeFileSync(file, updatedLines.join('\n'));
  });
}

module.exports = main;