/***
 * Copyright (c) 2016 - 2022 Alex Grant (@localnerve), LocalNerve LLC
 * Copyrights licensed under the BSD License. See the accompanying LICENSE file
 * for terms.
 */
'use strict';

var path = require('path');
var assetsJsonFile = './assets.json';
var assetsRevManifest = './assets-rev-manifest.json';

/**
 * Creates a configuration for loading and decorating assets json at a later
 * time. Assets json comes from webpack stats, generated by the build.
 *
 * @param {String} scriptsBaseDir - The base directory on which to join script
 * asset paths.
 * @param {String} revAssetBaseDir - The base directory on which to join revved
 * asset paths.
 * @returns {Object} The Config object used to load assets json and reference
 * assets.
 */
function assetsConfig (scriptsBaseDir, revAssetBaseDir) {
  /**
   * Creates Config Object
   *
   * @class
   * @param {String} scriptsDir - The base directory on which to join script
   * asset paths.
   */
  function Config (scriptsDir, revDir) {
    this.scriptsBaseDir = scriptsDir;
    this.revBaseDir = revDir;
  }

  Config.prototype = {
    /**
     * Loads webpack assets.json file, revManifest, and creates a filename
     * lookup table for revved assets. First unique filename wins.
     *
     * @returns {Object} A reference to the object instance for chainability.
     */
    load: function () {
      if (!this.assets) {
        var revManifest = require(assetsRevManifest);

        this.assets = {
          webpack: require(assetsJsonFile).assets,
          revManifest: revManifest,
          revBaseNames: Object.keys(revManifest).reduce(
            function (prev, curr) {
              var basename = path.basename(curr);
              if (!prev[basename]) {
                prev[basename] = revManifest[curr];
              }
              return prev;
            }, Object.create(null))
        };
      }
      return this;
    },

    /**
     * Loads assets json if not done, gets the main script asset name,
     * and joins it to the base directory.
     *
     * @returns {String} The main script asset file path.
     */
    mainScript: function () {
      this.load();
      var main = Array.isArray(this.assets.webpack.main) ?
        this.assets.webpack.main[0] : this.assets.webpack.main;
      return path.join(this.scriptsBaseDir, main);
    },

    /**
     * Loads assets json if not done, gets the sw-reg script asset name,
     * and joins it to the base directory.
     *
     * @returns {String} The sw-reg script asset file path.
     */
    swRegScript: function () {
      this.load();
      var swReg = Array.isArray(this.assets.webpack.swReg) ?
        this.assets.webpack.swReg[0] : this.assets.webpack.swReg;
      return path.join(this.scriptsBaseDir, swReg);
    },

    /**
     * Loads assets json if not done, gets the service-worker script asset name,
     * and joins it to the base directory.
     *
     * @param {Boolean} nameOnly - If true, only return the asset name, not
     * whole asset path.
     * @returns {String} The service-worker script asset file path.
     */
    swMainScript: function (nameOnly) {
      this.load();
      var sw = Array.isArray(this.assets.webpack.sw) ?
        this.assets.webpack.sw[0] : this.assets.webpack.sw;
      return nameOnly ? sw : path.join(this.scriptsBaseDir, sw);
    },

    /**
     * Same as swMainScript, but for the source map asset.
     *
     * @param {Boolean} nameOnly - If true, only return the asset name, not
     * whole asset path.
     * @returns {String} The service-worker source map if found.
     */
    swMainScriptMap: function (nameOnly) {
      this.load();
      var swMap = Array.isArray(this.assets.webpack.sw) ?
        this.assets.webpack.sw[1] : undefined;

      var swSourceMap;
      if (swMap) {
        swSourceMap = nameOnly ? swMap : path.join(this.scriptsBaseDir, swMap);
      }
      return swSourceMap;
    },

    /**
     * Get the path to a revved asset by its original name.
     *
     * @param {String} sourceName - The original name of the revved asset file.
     * Can be the filename (basename), or exact key in the revManifest.
     * @returns {String} full path to revved asset if found, undefined otherwise.
     */
    revAsset: function (sourceName) {
      this.load();

      var asset,
        revvedAsset = this.assets.revBaseNames[sourceName] ||
          this.assets.revManifest[sourceName];

      if (revvedAsset) {
        asset = path.join(this.revBaseDir, revvedAsset);
      }

      return asset;
    }
  };

  return new Config(scriptsBaseDir, revAssetBaseDir);
}

module.exports = {
  assetsJsonFile: assetsJsonFile,
  assetsRevManifest: assetsRevManifest,
  assetsConfig: assetsConfig
};
