const loaderUtils = require('loader-utils');
const glob = require('glob');

const path = require('path');

const fs = require('fs');

const precompile = require('./precompile');

function getLoaderConfig(loaderContext) {
  const query = loaderUtils.getOptions(loaderContext) || {};
  const configKey = query.config || 'handlebarsLoader';
  const config =
    (loaderContext.rootContext ? loaderContext.rootContext[configKey] : loaderContext.options[configKey]) || {};
  delete query.config;
  return {
    ...config,
    ...query
  };
}

const hardPreprocess = source => source.replace(/\{%\s+assign\b/g, '{% set');

const filenameWithoutExt = file => path.basename(file).split('.').slice(0, -1).join('.');

const readFile = filename => hardPreprocess(fs.readFileSync(filename, 'utf8'));

/**
 * returns an object where keys refer to the template name and values are the template content
 */
function resolveScript(scriptPath) {
  if (fs.existsSync(scriptPath)) {
    this.addDependency(scriptPath);
    return fs.readFileSync(scriptPath, { encoding: 'utf8' });
  }
  return '';
}
/**
 * returns an object where keys refer to the template name and values are the template content
 */
function resolveViews(viewsPath) {
  const sources = fs
    .readdirSync(viewsPath)
    .filter(name => name.endsWith('.liquid'))
    .map(name => {
      const filename = path.join(viewsPath, name);
      this.addDependency(filename);
      return [name.replace(/\.liquid$/, ''), readFile(filename)];
    });

  const partials = Object.fromEntries(sources);

  return partials;
}
/**
 * returns a json object with settings
 */
function resolveSettings(settingsPath) {
  return require(settingsPath);
}

/**
 * returns a list of locale objects { locale, translations, file }
 */
function resolveLocales(localesPath) {
  return glob.sync(localesPath).map(file => {
    const v = path.relative(path.resolve('.'), file);
    this.addDependency(v);

    const locale = filenameWithoutExt(file);
    const translations = require(file);
    return { locale, translations, file };
  });
}

module.exports = function (source) {
  const preprocessedSource = hardPreprocess(source);
  const { viewsPath, localesPath, settingsPath, scriptPath } = getLoaderConfig(this);

  const resolvePathRelativeToResource = p => path.resolve(path.dirname(this.resourcePath), p);

  const partials = viewsPath ? resolveViews.call(this, resolvePathRelativeToResource(viewsPath)) : undefined;
  const settings = settingsPath ? resolveSettings.call(this, resolvePathRelativeToResource(settingsPath)) : undefined;
  const locales = localesPath ? resolveLocales.call(this, resolvePathRelativeToResource(localesPath)) : undefined;
  const script = scriptPath ? resolveScript.call(this, resolvePathRelativeToResource(scriptPath)) : undefined;

  return `
  /**
   * Returns a template generator
   * 
   * @param html
   * @param repeat
   * @param unsafeHTML
   */
  export default ${precompile(preprocessedSource, partials, locales, settings, 'en', script)};`;
};
