import proc from "node:child_process";
import fs from "node:fs/promises";
import ph from "node:path";
import url from "node:url";
import * as sass from "sass-embedded";
import log from "fancy-log";

import wpool from "workerpool";
import postcss from "postcss";
import modulesProcessor from "postcss-modules";
import autoprefixerProcessor from "autoprefixer";

const compiler = await sass.initAsyncCompiler();

async function compileFile(path) {
  const dir = ph.dirname(path);
  const name = ph.basename(path, ".scss");
  const dest = `${dir}${ph.sep}${name}.css`;


  return new Promise(async (resolve, reject) => {
    try {
      const result = await compiler.compileAsync(path, {
        loadPaths: ["node_modules/animate.css", "resources/styles/common/", "resources/styles"],
        sourceMap: false
      });
      // console.dir(result);
      resolve({
        inputPath: path,
        outputPath: dest,
        css: result.css
      });
    } catch (cause) {
      // console.error(cause);
      reject(cause);
    }
  });
}

function configureModulesProcessor(options) {
  const ROOT_NAME = "app";

  return modulesProcessor({
    getJSON: (cssFileName, json, outputFileName) => {
      // We do nothing because we don't want the generated JSON files
    },
    // Calculates the whole css-module selector name.
    // Should be the same as the one in the file `/src/app/main/style.clj`
    generateScopedName: (selector, filename, css) => {
      const dir = ph.dirname(filename);
      const name = ph.basename(filename, ".css");
      const parts = dir.split("/");
      const rootIdx = parts.findIndex((s) => s === ROOT_NAME);
      return parts.slice(rootIdx + 1).join("_") + "_" + name + "__" + selector;
    },
  });
}

function configureProcessor(options={}) {
  const processors = [];

  if (options.modules) {
    processors.push(configureModulesProcessor(options));
  }
  processors.push(autoprefixerProcessor);

  return postcss(processors);
}

async function postProcessFile(data, options) {
  const proc = configureProcessor(options);

  // We compile to the same path (all in memory)
  const result = await proc.process(data.css, {
    from: data.outputPath,
    to: data.outputPath,
    map: false,
  });

  return Object.assign(data, {
    css: result.css
  });
}

async function compile(path, options) {
  let result = await compileFile(path);
  return await postProcessFile(result, options);
}

wpool.worker({
  compileSass: compile
}, {
  onTerminate: async (code) => {
    // log.info("worker: terminate");
    await compiler.dispose();
  }
});