const esbuild = require("esbuild");
const path = require("path");
const fs = require("fs");
const { execSync, spawn } = require("child_process");

// colors for console output
const consoleColors = {
  info: "\x1b[34m", // Blue
  success: "\x1b[32m", // Green
  warning: "\x1b[33m", // Yellow
  error: "\x1b[31m", // Red
  reset: "\x1b[0m", // Reset
};

const createDefinitions = process => {
  return Object.keys(process.env).reduce((acc, key) => {
    acc[`process.env.${key}`] = JSON.stringify(process.env[key]);
    return acc;
  }, {});
};

const entryPoint = file => path.join(process.cwd(), file);

const writeMetafile = (metafile, outdir) => {
  const metaFilePath = path.join(outdir, "meta.json");
  fs.writeFileSync(metaFilePath, JSON.stringify(metafile, null, 2));
  return metaFilePath;
};

const generateBundleReport = async (metaFilePath, outdir) => {
  try {
    console.info(
      `${consoleColors.info}[bundle-analyzer]${consoleColors.reset} Generating bundle report...`
    );

    const htmlFilePath = path.join(outdir, "bundle-report.html");
    execSync(
      `npx esbuild-visualizer --metadata ${metaFilePath} --filename ${htmlFilePath}`,
      { stdio: "inherit" }
    );

    console.info(
      `${consoleColors.success}[bundle-analyzer]${consoleColors.reset} Bundle report generated at ${htmlFilePath}`
    );

    const command = process.platform === "win32" ? "start" : "open";
    spawn(command, [htmlFilePath], { detached: true, stdio: "ignore" });
    console.info(
      `${consoleColors.success}[bundle-analyzer]${consoleColors.reset} Bundle report opened in browser`
    );

    return htmlFilePath;
  } catch (error) {
    console.error(
      `${consoleColors.error}[bundle-analyzer]${consoleColors.reset} Failed to generate bundle report: ${error.message}`
    );
    throw error;
  }
};

const build = async config => {
  try {
    console.info(
      `${consoleColors.info}[esbuild]${consoleColors.reset} Building...`
    );

    const result = await esbuild.build(config);

    if (result.metafile) {
      const metaFilePath = writeMetafile(result.metafile, config.outdir);
      await generateBundleReport(metaFilePath, config.outdir);
    }

    console.info(
      `${consoleColors.success}[esbuild]${consoleColors.reset} Build successful`
    );
  } catch (error) {
    console.error(`Build error: ${error.message}`);
    const errorMessage = `${consoleColors.error}[esbuild]${consoleColors.reset} Build failed`;
    throw new Error(errorMessage);
  }
};

const watch = async config => {
  const ctx = await esbuild.context(config);
  await ctx.watch();
  await ctx.serve({
    servedir: config.outdir,
    port: parseInt(process.env.DEVSERVER_PORT || "8000"),
  });
};

module.exports = {
  consoleColors,
  createDefinitions,
  entryPoint,
  build,
  watch,
};
