/**
 * Niwa AI — frontend asset build (concat + minify).
 *
 * Produces minified bundles in assets/dist/ that the asset loader serves
 * instead of the raw per-module files. Goal: fewer HTTP requests + smaller
 * parse cost on first load (especially mobile). Behavior is preserved —
 * this only concatenates (in dependency order) and minifies; it never
 * rewrites module logic, and it does not touch animations.
 *
 * Usage:  node build/build-frontend.mjs   (or `npm run build:assets`)
 *
 * The vanilla modules are plain IIFE scripts that attach to window.Niwa.*,
 * so ordered concatenation is equivalent to enqueuing them in sequence.
 * Files are joined with `\n;\n` so no ASI hazard can merge two modules.
 */

import { transform } from 'esbuild';
import { readFile, writeFile, mkdir, stat } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import path from 'node:path';

const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const JS = (p) => path.join(ROOT, 'assets/js', p);
const CSS = (p) => path.join(ROOT, 'assets/css', p);
const DIST = path.join(ROOT, 'assets/dist');

/* Core JS — always loaded on the frontend, in dependency/enqueue order. */
const CORE_JS = [
  'modules/utils.js',
  'modules/theme-switcher.js',
  'modules/scroll-behavior.js',
  'modules/morph-controller.js',
  'modules/message-renderer.js',
  'modules/form-handler.js',
  'modules/product-manager.js',
  'modules/product-experience.js',
  'modules/chat-client.js',
  'niwa-app.js',
  'niwa-cb-shim.js',
  'niwa-activity.js',
].map(JS);

/* Core CSS — always loaded, cascade order matters (shield stays separate/last). */
const CORE_CSS = [
  'niwa-tokens.css',
  'niwa-reset.css',
  'niwa-theme-light.css',
  'niwa-theme-dark.css',
  'niwa-theme-neutral.css',
  'niwa-layout.css',
  'niwa-animations.css',
  'niwa-morph.css',
  'niwa-centerstage.css',
  'niwa-messages.css',
  'niwa-typing.css',
  'niwa-actions.css',
  'niwa-input-bar.css',
  'niwa-badges.css',
  'niwa-scrollbar.css',
  'niwa-products.css',
  'niwa-attention.css',
].map(CSS);

/* Lead Form Generator JS — conditional bundle (engine → chat-mode → card-mode). */
const LEAD_FORM_JS = [
  'modules/scheduler.js',
  'modules/lead-form-engine.js',
  'modules/lead-form-chat-mode.js',
  'modules/lead-form-card-mode.js',
].map(JS);

async function concat(files, joiner) {
  const parts = await Promise.all(files.map((f) => readFile(f, 'utf8')));
  return parts.join(joiner);
}

async function buildJs(files, outName) {
  const source = await concat(files, '\n;\n');
  const { code, warnings } = await transform(source, {
    loader: 'js',
    minify: true,
    legalComments: 'none',
    // No `target` downlevel: keep ES5-ish code valid as authored.
  });
  warnings.forEach((w) => console.warn(`  [js warn] ${outName}: ${w.text}`));
  const out = path.join(DIST, outName);
  await writeFile(out, code, 'utf8');
  return reportSize(out, source.length, code.length);
}

async function buildCss(files, outName) {
  const source = await concat(files, '\n');
  const { code, warnings } = await transform(source, {
    loader: 'css',
    minify: true,
    legalComments: 'none',
  });
  warnings.forEach((w) => console.warn(`  [css warn] ${outName}: ${w.text}`));
  const out = path.join(DIST, outName);
  await writeFile(out, code, 'utf8');
  return reportSize(out, source.length, code.length);
}

function reportSize(out, rawLen, minLen) {
  const pct = rawLen > 0 ? Math.round((1 - minLen / rawLen) * 100) : 0;
  const name = path.basename(out);
  console.log(
    `  ${name.padEnd(34)} ${(rawLen / 1024).toFixed(1)}KB → ${(minLen / 1024).toFixed(1)}KB  (-${pct}%)`
  );
  return { name, rawLen, minLen };
}

async function main() {
  await mkdir(DIST, { recursive: true });
  console.log('Building Niwa frontend bundles → assets/dist/');

  console.log('\nJS:');
  await buildJs(CORE_JS, 'niwa-frontend.min.js');
  await buildJs(LEAD_FORM_JS, 'niwa-lead-form.min.js');
  await buildJs([JS('modules/scheduler.js')], 'niwa-scheduler.min.js');
  await buildJs([JS('conversion-busters.js')], 'conversion-busters.min.js');
  await buildJs([JS('attention-capture.js')], 'attention-capture.min.js');
  await buildJs([JS('leave-stoper.js')], 'leave-stoper.min.js');
  await buildJs([JS('traffic-collector.js')], 'traffic-collector.min.js');

  console.log('\nCSS:');
  await buildCss(CORE_CSS, 'niwa-frontend.min.css');
  await buildCss([CSS('niwa-lead-form.css')], 'niwa-lead-form.min.css');
  await buildCss([CSS('niwa-frontend-shield.css')], 'niwa-frontend-shield.min.css');

  console.log('\nDone.');
}

main().catch((err) => {
  console.error('Build failed:', err);
  process.exit(1);
});
