import commonjs from "@rollup/plugin-commonjs";
import { nodeResolve as resolve } from "@rollup/plugin-node-resolve";
import external from "rollup-plugin-peer-deps-external";

import fs from 'fs-extra';
import path from 'path';

const DEVELOPMENT = process.env.DEVELOPMENT ? true : false;
const FLOWNET_WATCH = process.env.FLOWNET_WATCH ? true : false;

const extensions = [".ts", ".tsx", ".js", ".jsx", ".json"];

{% if atom.doc.features.copy_enabled===true %}
const copyFiles = async (src, dest) => {
  try {
    await fs.copy(src, dest);
    console.log(`Copied files from ${src} to ${dest}`);
  } catch (err) {
    console.error('Error copying files:', err);
  }
};

const watchFiles = async (targets) => {
  const chokidar = await import('chokidar');
  targets.forEach(target => {
    const watcher = chokidar.watch(target.src, { persistent: true });

    watcher.on('add', async filePath => {
      const destPath = target.dest;
      const relativePath = path.relative(path.dirname(target.src), filePath);
      await copyFiles(filePath, path.join(destPath, relativePath));
    });

    watcher.on('change', async filePath => {
      const destPath = target.dest;
      const relativePath = path.relative(path.dirname(target.src), filePath);
      await copyFiles(filePath, path.join(destPath, relativePath));
    });

    watcher.on('unlink', async filePath => {
      const destPath = target.dest;
      const relativePath = path.relative(path.dirname(target.src), filePath);
      try {
        await fs.remove(path.join(destPath, relativePath));
        console.log(`Removed files from ${path.join(destPath, relativePath)}`);
      } catch (err) {
        console.error('Error removing files:', err);
      }
    });
  });
};
{% endif %}

const initPlugins = async (options) => {
  const plugins = [];

  {# DELETE #}
  if (options.delete) {
    const {default:del} = await import('@fnet/rollup-plugin-delete');
    plugins.push(del(options.delete));
  }

  {# REPLACE #}
  if (options.replace) {
    const {default:replace} = await import("@rollup/plugin-replace");
    plugins.push(replace({
      "process.env.NODE_ENV": JSON.stringify(DEVELOPMENT ? 'development' : 'production'),
      preventAssignment: true,
      ...options.replace
    }));
  }

  {# ALIAS #}
  if (options.alias) {
    const {default:alias} = await import('@rollup/plugin-alias');
    plugins.push(alias(options.alias));
  }

  {# NUNJUCKS #}
  {% if atom.doc.features.nunjucks_enabled===true %}
  if (options.nunjucks) {
    const {default:nunjucks} = await import('@fnet/rollup-plugin-nunjucks');
    plugins.push(nunjucks(options.nunjucks.options));
  }
  {% endif %}

  {# COPY #}
  {% if atom.doc.features.copy_enabled===true %}
  if (options.copy) {
    const {default:copy} = await import('rollup-plugin-copy');
    plugins.push(copy(options.copy.options));

    if (FLOWNET_WATCH) watchFiles(options.copy.options.targets);
  }
  {% endif %}

  {# STRING #}
  {% if atom.doc.features.string_enabled===true %}
  if (options.string) {
    const { string } = await import('rollup-plugin-string');
    plugins.push(string(options.string.options));
  }
  {% endif %}

  {# IMAGE #}
  {% if atom.doc.features.image_enabled===true %}
  if (options.image) {
    const {default:image} = await import('@rollup/plugin-image');
    plugins.push(image(options.image.options));
  }
  {% endif %}

  {# WASM #}
  {% if atom.doc.features.wasm_enabled===true %}
  if (options.wasm) {
    const { wasm } = await import('@rollup/plugin-wasm');
    plugins.push(wasm(options.wasm.options));
  }
  {% endif %}

  {# POSTCSS #}
  {% if atom.doc.features.css_enabled===true %}
  if (options.postcss) {
    const {default:postcss} = await import('rollup-plugin-postcss');
    const { plugins: cssPlugins, ...cssOptions } = options.postcss.options;
    const postcssPlugins = [];

    if (cssPlugins) {
      for (const plugin of cssPlugins) {
        let pluginLib;
        switch (plugin.name) {
          case "postcss-import":
            pluginLib = (await import("postcss-import")).default;
            break;
          case "postcss-url":
            pluginLib = (await import("postcss-url")).default;
            break;
          case "postcss-preset-env":
            pluginLib = (await import("postcss-preset-env")).default;
            break;
          case "autoprefixer":
            pluginLib = (await import("autoprefixer")).default;
            break;
          case "cssnano":
            pluginLib = (await import("cssnano")).default;
            break;
          default:
            continue;
        }
        postcssPlugins.push(pluginLib(plugin.options));
      }
    }

    plugins.push(postcss({
      ...cssOptions,
      plugins: postcssPlugins
    }));
  }
  {% endif %}

  {# JSON #}
  {% if atom.doc.features.json_enabled===true %}
  if (options.json) {
    const {default:json} = await import('@rollup/plugin-json');
    plugins.push(json(options.json.options));
  }
  {% endif %}

  {# EXTERNAL #}
  plugins.push(external({
    includeDependencies: !options.browser
  }));

  {# RESOLVE #}
  plugins.push(resolve({
    extensions: extensions,
    browser: options?.browser === true,
    preferBuiltins: true,
    modulePaths: ['./node_modules']
  }));

  {# COMMONJS #}
  plugins.push(commonjs({
    {% if atom.doc.features.project.format ==='esm' %}
    include: /node_modules/,
    ignore: ["fsevents"],
    {% endif %}
  }));


  {# POLYFILL #}
  {% if atom.doc.features.polyfill_enabled===true %}
  if(options.polyfill){
    const {default:polyfills} = await import('rollup-plugin-node-polyfills');
    plugins.push(polyfills(options.polyfill.options));
  }
  {% endif %}

  {# WORKBOX #}
  {% if atom.doc.features.workbox_enabled===true %}
  if (options?.workbox) {
    const {generateSW,injectManifest} = await import('rollup-plugin-workbox');
    if(options.workbox.options?.generate) plugins.push(generateSW(options.workbox.options.generate));
    if(options.workbox.options?.inject) plugins.push(injectManifest(options.workbox.options.inject));
  }
  {% endif %}

  {# BABEL #}
  {% if atom.doc.features.babel_enabled===true %}
  if (options?.babel) {
    const { babel } = await import('@rollup/plugin-babel');
    plugins.push(
      babel({
        babelHelpers: "bundled",
        presets: [
          ["@babel/preset-env", {
            targets: options.babel.targets || "defaults",
          }],
          ["@babel/preset-react"]
        ],
        extensions: extensions,
        exclude: "node_modules/**",
        plugins: options.babel.plugins || [],
        sourceMaps: DEVELOPMENT
      })
    );
  }
  {% endif %}

  {# TERSER #}
  {% if atom.doc.features.terser_enabled===true %}
  if (options.terser) {
    const {default:terser} = await import("@rollup/plugin-terser");
    plugins.push(terser(options.terser.options));
  }
  {% endif %}

  {# GZIP #}
  {% if atom.doc.features.gzip_enabled===true %}
  if (options.gzip) {
    const {default:gzip} = await import('rollup-plugin-gzip');
    if(options.gzip.options) plugins.push(gzip(options.gzip.options));
  }
  {% endif %}

  {# ANALYZER #}
  {% if atom.doc.features.analyzer_enabled===true %}
  if (options.analyzer) {
    const { default: analyzer } = await import("rollup-plugin-analyzer");
    plugins.push(analyzer(options.analyzer.options));
  }
  {% endif %}

  {# VISUALIZER #}
  {% if atom.doc.features.visualizer_enabled===true %}
  if (options.visualizer) {
    const { visualizer } = await import("rollup-plugin-visualizer");
    plugins.push(visualizer(options.visualizer.options));
  }
  {% endif %}

  {# BROWSERSYNC #}
  {% if atom.doc.features.browsersync_enabled===true %}
  if (options.browsersync && FLOWNET_WATCH) {
    const {default:browsersync} = await import('@fnet/rollup-plugin-browsersync');
    options.browsersync.middleware = function (req, res, next) {
      if (req.method === 'OPTIONS') {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
        res.setHeader('Access-Control-Allow-Credentials', true);
        res.end();
      } else {
        next();
      }
    };
    plugins.push(browsersync(options.browsersync));
  }
  {% endif %}

  return plugins;
}

const groups = [
  { name: "default" }
];

const configs = [];

const createConfigs = async () => {
  for (const group of groups) {
    let groupDir = path.normalize(`./dist/${group.name}/`);
    if (!fs.existsSync(groupDir)) {
      fs.mkdirSync(groupDir, { recursive: true });
    }

    {% for key, value in atom.doc.features.rollup_output %}
    {% if value and value.enabled !== false %}
    {
      // {{key | upper}}
      const config = {
        input: path.normalize(`{{value.input or 'src/${group.name}/index.js'}}`),
        output: {
          dir: path.normalize(`{{value.output_dir or 'dist/${group.name}/' + key}}`),
          format: "{{value.format}}",
          {% if atom.doc.features.sourcemap === true %}
          sourcemap: true,
          {% endif %}
          {% if value.format === 'cjs' %}
          exports: "{{value.output_exports or 'named'}}",
          interop: "auto",
          entryFileNames: "[name].cjs",
          chunkFileNames: "[name]-[hash].cjs",
          {% endif %}
          {# BEGIN: rollup_config_output_name #}
          {% if value.format==='iife' or value.format==='umd'%}
          name: "{{atom.doc.bundleName}}",
          {% endif %}
          {# END: rollup_config_output_name #}
          {# BEGIN: rollup_config_output_globals #}
          {% if value.browser===true %}
          {% if value.globals.length %}
          globals: {
              {% for global in value.globals %}
                  "{{global.key}}":"{{global.value}}" {% if not loop.last %},{% endif %}
              {% endfor %}
          },
          {% endif %}
          {% endif %}
          {# END: rollup_config_output_globals #}
          {# BEGIN: rollup_config_output_banner #}
          {% if value.banner %}
          banner:'{{value.banner}}',
          {% endif %}
          {# END: rollup_config_output_banner #}
          {# BEGIN: rollup_config_output_footer #}
          {% if value.format==='iife' %}
              {% if atom.type==='workflow'%}
              {# footer: "new {{atom.doc.bundleName}}().run().catch(e=>{});" #}
              {% endif %}
          {% endif %}
          {# END: rollup_config_output_footer #}
        },
        {% if value.context %}
        context: "{{value.context}}",
        {% endif %}
        {# BEGIN: rollup_config_external #}
        {% if value.external_enabled %}
        external: [
            {% for external in value.external %}
                "{{external}}" {% if not loop.last %},{% endif %}
            {% endfor %}
        ],
        {% endif %}
        {# END: rollup_config_external #}
        {# BEGIN: rollup_config_onwarn #}
        onwarn(warning, warn) {
            switch (warning.code) {
            case 'MODULE_LEVEL_DIRECTIVE':
            case 'CIRCULAR_DEPENDENCY':
                return;
            default:
                warn(warning);
            }
        },
        {# END: rollup_config_onwarn #}
        {# BEGIN: rollup_config_plugins #}
        plugins: await initPlugins({
            delete:{ targets: [path.normalize(groupDir + '{{key}}')], runOnce: DEVELOPMENT },

            format:"{{ value.format }}",

            {% if value.babel===true %}
            babel:{{value.babel_options | dump | safe}},
            {% endif %}

            {% if value.replace ===true %}
            replace:{{value.replace_options | dump | safe}},
            {% endif %}

            {% if value.browser===true %}
            browser:true,
            {% endif %}

            {% if value.browsersync===true and atom.doc.features.browsersync_enabled===true%}
            browsersync: {{value.browsersync_options | dump | safe}},
            {% endif %}

            {% if value.alias_enabled===true %}
            alias:{{value.alias | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.css %}
            postcss:{{value.css | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.copy %}
            copy:{{value.copy | dump | safe}},
            {% endif %}

            {# OK #}
            {% if  value.terser%}
            terser:{{value.terser | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.json %}
            json:{{value.json | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.wasm %}
            wasm: {{value.wasm | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.string %}
            string:{{value.string | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.image %}
            image:{{value.image | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.analyzer %}
            analyzer:{{value.analyzer | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.visualizer %}
            visualizer:{{value.visualizer | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.polyfill %}
            polyfill:{{value.polyfill | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.nunjucks %}
            nunjucks:{{value.nunjucks | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.workbox %}
            workbox:{{value.workbox | dump | safe}},
            {% endif %}

            {# OK #}
            {% if value.gzip %}
            gzip:{{value.gzip | dump | safe}},
            {% endif %}
        }),
        {# END: rollup_config_plugins #}
      }
      configs.push(config);
    }
    {% endif %}
    {% endfor %}
  }

  {# DTS #}
  {% if atom.doc.features.dts_enabled ===true %}
    const { dts } = await import("rollup-plugin-dts");
    const typesConfig = {
      input: path.normalize('{{atom.typesDir}}/default/index.d.ts'),
      output: {
        file: path.normalize("./dist/default/types/index.d.ts"),
        format: "es"
      },
      plugins: [dts()],
    }
    configs.push(typesConfig);
  {% endif %}
}

{% if atom.doc.features.render and atom.doc.features.render.enabled !== false  %}
async function render(){
  const { default:fnetRender } = await import('@flownet/lib-render-templates-dir');

  const dirs={{atom.doc.features.render.dirs | default([]) | dump | safe}};

  for (const dir of dirs) {
    await fnetRender(dir);
  }
}
{% endif %}
export default async () => {
  {% if atom.doc.features.render and atom.doc.features.render.enabled !== false  %}
  await render();
  {% endif %}
  await createConfigs();
  return configs;
};