/**
 * Build-time guard for the themes gallery (`docs/themes.mdx` / <ThemeGallery/>).
 *
 * This plugin does NOT expose the manifest via setGlobalData/usePluginData.
 * That mechanism bundles a plugin's entire payload into Docusaurus's shared
 * main.js runtime chunk - fetched on every page of the site, forever, since
 * usePluginData needs the data synchronously available everywhere. That is
 * fine for plugins/segments' small registry.json, but 124 inlined SVGs is a
 * different order of magnitude: measured, it added ~34KB gzip to main.js
 * itself, paid by every visitor on every page, not just /docs/themes.
 *
 * Instead, <ThemeGallery/> loads generated/themes.json itself via a plain
 * static import (see that component's own comment): webpack code-splits a
 * plain import into the page's own chunk without any special plugin
 * machinery, and being synchronous rather than a dynamic import(), it needs
 * no Loadable()/preloadAll trick to resolve during Docusaurus's SSR build
 * step either - the static HTML still has every theme inlined. This plugin
 * exists only to fail the build early with an actionable message if that file
 * is missing or malformed - the same guard plugins/segments' readRegistry
 * performs for its own generated file - rather than a deep webpack/React error
 * only surfacing once <ThemeGallery/> actually renders.
 */

const path = require('path');

const { readGeneratedJson, readGeneratedArray } = require('../readGeneratedJson');

const MANIFEST_PATH = path.join(__dirname, '../../generated/themes.json');
// Written by the same npm script as the manifest, holding two renders of the built-in default
// config for the homepage (see export_themes.mjs's HERO_FILE): svg for dark mode, svgLight for
// light mode - the homepage (src/pages/index.js) picks between them via CSS keyed off
// Docusaurus's own html[data-theme] attribute, not by re-rendering client-side. Unlike a manifest
// entry there is no theme name or themes/ file behind either render, because that config is
// built in Go. Guarded here for the same reason the manifest is: a missing or malformed file
// should fail the build with a note saying which command writes it, not as a webpack error once
// <Home/> renders.
const HERO_PATH = path.join(__dirname, '../../generated/hero.json');

const GENERATED_BY = 'This file is generated by `npm run themes` (which shells out to an oh-my-posh binary on ' +
  'PATH), not written by hand. Run it, then re-run the website build.';

const THEME_FORMATS = ['json', 'toml', 'yaml'];

function isThemeEntry(entry) {
  return entry
    && typeof entry.name === 'string'
    && typeof entry.githubUrl === 'string'
    && typeof entry.rawConfigUrl === 'string'
    && THEME_FORMATS.includes(entry.format)
    && typeof entry.svg === 'string'
    && typeof entry.svgLight === 'string';
}

function validateHero() {
  const hero = readGeneratedJson(HERO_PATH, 'oh-my-posh-themes', GENERATED_BY);

  if (!hero || typeof hero.svg !== 'string' || !hero.svg || typeof hero.svgLight !== 'string' || !hero.svgLight) {
    throw new Error(
      `oh-my-posh-themes plugin: malformed ${HERO_PATH}: ${JSON.stringify(hero)}. ` +
      'Expected { svg, svgLight }.',
    );
  }
}

function validateManifest() {
  const themes = readGeneratedArray(MANIFEST_PATH, 'oh-my-posh-themes', GENERATED_BY);

  const seen = new Set();

  for (const entry of themes) {
    if (!isThemeEntry(entry)) {
      throw new Error(
        `oh-my-posh-themes plugin: malformed entry in ${MANIFEST_PATH}: ${JSON.stringify(entry)}. ` +
        'Expected { name, githubUrl, rawConfigUrl, format, svg, svgLight }.',
      );
    }

    if (seen.has(entry.name)) {
      throw new Error(`oh-my-posh-themes plugin: duplicate theme name "${entry.name}" in ${MANIFEST_PATH}.`);
    }

    seen.add(entry.name);
  }
}

module.exports = function themesPlugin() {
  return {
    name: 'oh-my-posh-themes',

    async loadContent() {
      validateManifest();
      validateHero();
    },
  };
};
