import { defineConfig, type Plugin } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'node:path';

/**
 * The admin bundle is loaded by WordPress from a hashed filename resolved
 * through Vite's manifest, so PHP never needs to know the build output names.
 *
 * React is bundled rather than mapped onto WordPress's own `wp-element`. The
 * editor will depend on React Flow, Zustand and TanStack Query, all of which
 * expect a React they control the version of; inheriting whatever React a given
 * WordPress release ships is not a trade worth making for a few kilobytes.
 */
/**
 * React Flow's credit on the canvas links to reactflow.dev with a query string
 * in production builds, and no link the plugin ships may carry a tracking
 * parameter (WordPress.org guideline 7). So the credit stays, as the bare
 * address, and the build fails if the library ever builds that link another
 * way and a query comes back. The release build checks every file in the zip
 * for tracking parameters too (bin/build-zip.php).
 */
function plainReactFlowCredit(): Plugin {
  const site = 'https://reactflow.dev';

  return {
    name: 'flowwp-plain-react-flow-credit',
    transform(code, id) {
      if (!id.includes('@xyflow')) {
        return null;
      }

      // Built as `https://reactflow.dev${…}`: a query in production, a path
      // otherwise. Either way, the bare address.
      const plain = code.replace(/`https:\/\/reactflow\.dev\$\{[^}]*\}`/g, `'${site}'`);

      return plain === code ? null : { code: plain, map: null };
    },
    generateBundle(_options, bundle) {
      for (const [name, output] of Object.entries(bundle)) {
        if (output.type === 'chunk' && output.code.includes(`${site}?`)) {
          this.error(`${name} links to ${site} with a query string.`);
        }
      }
    },
  };
}

export default defineConfig({
  plugins: [react(), plainReactFlowCredit()],
  root: resolve(__dirname, 'admin'),
  base: '',
  resolve: {
    // Mirrors the `@/*` path mapping in tsconfig.json. Both have to agree or
    // the type-check passes and the build fails.
    alias: {
      '@': resolve(__dirname, 'admin/src'),
    },
  },
  build: {
    manifest: true,
    outDir: resolve(__dirname, 'admin/dist'),
    emptyOutDir: true,
    target: 'es2020',
    sourcemap: false,
    rollupOptions: {
      input: resolve(__dirname, 'admin/src/main.tsx'),
      // @wordpress/i18n is deliberately NOT a dependency here. It is already on
      // the page as the `wp-i18n` script, and a bundled second copy would carry
      // its own empty translation store: wp_set_script_translations() fills
      // WordPress's, and ours would never see a word of it. src/lib/i18n.ts
      // reads the global instead, which is the same object WordPress loaded the
      // strings into.
      // Do not add `inlineDynamicImports` here. Freemius strips premium code
      // from the free build textually, and minified bundles have neither the
      // comments its markers need nor a syntactically removable unit left to
      // cut — so premium UI, when we have any, has to live in its own
      // dynamically imported chunk whose filename carries `__premium_only`.
      // Inlining chunks would put it back in the main bundle and break that
      // silently, in the free build only. See docs/FREEMIUS-PACKAGING.md.
    },
  },
});
