"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _webpackSources = require("webpack-sources");

var _utils = require("../utils");

var _path = _interopRequireDefault(require("path"));

var _getI18nFileUrlPathTemplate = require("./I18nSplitPlugin/utils/getI18nFileUrlPathTemplate");

var _I18nKeysIdentifer = _interopRequireDefault(require("./I18nSplitPlugin/I18nKeysIdentifer"));

var _replaceCssDirTemplate = require("./RtlSplitPlugin/replaceCssDirTemplate");

var _EFCTemplatePlugin = _interopRequireDefault(require("./EFCTemplatePlugin"));

var _logger = require("../logger");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

// import { getShortI18nAssets } from './I18nSplitPlugin/utils/hashUtils';
const cliOptions = (0, _utils.getOptions)();
const {
  app: {
    publicPaths
  },
  i18n: {
    chunkSplitEnable
  },
  css: {
    enableRTLSplit
  },
  efc: efcOptios
} = cliOptions;
const {
  createSDkFile,
  cdnStatement
} = efcOptios;

class EFCPlugin {
  constructor(options = {}) {
    this.isDevelopment = options.isDevelopment;
    this.templateFilePath = options.templateFilePath;
    this.serverUrl = options.serverUrl;
    this.i18nFileNameTemplate = options.i18nFileNameTemplate; // NOTE: this logic may be needed for i18n splited file name with contenthash cases
    // this.i18nManifestFileName = options.i18nManifestFileName;
    // IMPORTANT: here we mergeing optionds  from  pacakge.json  and options via constructor
    // So when debugging consider this as well

    this.options = Object.assign({}, efcOptios, options);
    this.options.entryPointName = options.entryPointName || 'efc';
    this.options.outputFile = efcOptios.outputFile.replace('[version]', efcOptios.version);
    this.options.nameScope = options.nameScope || 'EFComponents';
    const localeAttr = this.options.localeAttr || 'data-efc-locale';
    const cssDirAttr = this.options.cssDirAttr || 'data-efc-dir';
    const localeDefaultValue = this.options.localeDefaultValue || 'en_US';
    const cssDirDefaultValue = this.options.cssDirDefaultValue || 'ltr';
    this.options.localeStatement = options.localeStatement || // Statment 1:   return langEle && langEle.getAttribute('${localeAttr}') || 'en_US';
    // Statment 2:   return langEle ? langEle.getAttribute('${localeAttr}') : 'en_US';
    // We are using statement1 not statment2,
    // Because even that attribute doesn't have value, We need default value
    `(() => {
        let langEle = document.querySelector('[${localeAttr}]');
        return langEle && langEle.getAttribute('${localeAttr}') || '${localeDefaultValue}';
      })();`;
    this.options.cssDirStatement = options.cssDirStatement || `(() => {
        let dirEle = document.querySelector('[${cssDirAttr}]');
        return dirEle && dirEle.getAttribute('${cssDirAttr}') || '${cssDirDefaultValue}';
      })();`;
  } // NOTE: this logic may be needed for i18n splited file name with contenthash cases
  // getI18nManifest(compilation) {
  //   const i18nManifestFile =
  //     compilation.assets[this.options.i18nManifestFileName];
  //   if (i18nManifestFile) {
  //     const manifest = JSON.parse(i18nManifestFile.source());
  //     return manifest;
  //   }
  //   return {};
  // }


  getI18nAssetsStr(entryPoint, compilation) {
    if (!chunkSplitEnable) {
      let i18nAsstes = {};
      const i18nFiles = Object.keys(compilation.assets).filter(assert => assert.indexOf(`i18n${_path.default.sep}`) !== -1); //hook for i18n url contains i18n/ may cause problem

      i18nAsstes = i18nFiles.reduce((res, i18nFilePath) => {
        const fileName = i18nFilePath.replace(`i18n${_path.default.sep}`, '');
        const splittedFileName = fileName.split('.');
        res[splittedFileName[0]] = i18nFilePath;
        return res;
      }, {});
      return `[${JSON.stringify(i18nAsstes)}[lang]]`;
    }

    const initalI18nAssets = entryPoint.chunks.filter(chunk => _I18nKeysIdentifer.default.isChunkHasI18n(chunk)).map(chunk => (0, _getI18nFileUrlPathTemplate.getI18nFileUrlPathTemplate)(compilation, chunk, this.i18nFileNameTemplate, '@locale@'));
    return `${JSON.stringify(initalI18nAssets)}.map(urlpath => urlpath.replace(/@locale@/g, lang))`;
  }

  createFileContent(compilation) {
    const {
      entryPointName,
      localeStatement,
      cssDirStatement,
      nameScope,
      cdnVariableName = null
    } = this.options;
    const {
      serverUrl
    } = this;
    const cssDirTemplate = '@dir@'; // const i18nManifest = this.getI18nManifest(compilation);

    const entryPoint = compilation.entrypoints.get(entryPointName); // const chunk = compilation.namedChunks.get(entryPointName);

    const [jsPath, cssPath,,, i18nJsPath] = !this.isDevelopment ? publicPaths : [];
    const initialFiles = entryPoint.getFiles();
    const filteredInitialFiles = initialFiles.filter(file => /\.(css|js)$/.test(file)); // const i18nAssets = getShortI18nAssets(
    //   entryPoint.chunks,
    //   i18nManifest,
    //   i18nJsPath
    // );

    const initalI18nAssets = this.getI18nAssetsStr(entryPoint, compilation, i18nJsPath);
    return `(() => {
  const lang = ${localeStatement};
  ${enableRTLSplit ? `const cssDir = ${cssDirStatement};` : ''}
  const prod = !${this.isDevelopment};
  let cdnVariableName = "${cdnVariableName}";

  function getAssetUrl(ext) {
    ${cdnStatement ? `
    return (() => {
      let fu = (${cdnStatement});
      return typeof fu === "function" ? fu(ext) : fu;
    })();` : ''}

    ${publicPaths.callback ? `return (${publicPaths.callback})(ext)` : ''}
    
    let assetURLs = {
      //hook
      js: ${JSON.stringify(jsPath || serverUrl)},
      css: ${JSON.stringify(cssPath || serverUrl)},
      i18n: ${JSON.stringify(i18nJsPath || serverUrl)}
    };

    return assetURLs[ext];

  }
  

  window.desk_urls={}
  window.desk_urls.staticDomain = 'https:' + getAssetUrl('js') + '/';
  if (prod && cdnVariableName) {
    window["${cdnVariableName}"] = 'https:' + getAssetUrl('css') + '/';
  }

  let initalI18nAssets = ${initalI18nAssets};
  let initialAssets = initalI18nAssets.concat(${JSON.stringify(enableRTLSplit ? filteredInitialFiles.map(filePath => (0, _replaceCssDirTemplate.replaceCssDirTemplate)(filePath, cssDirTemplate)) : filteredInitialFiles)});

  let loadAsset = (id, type, url) => {
    return new Promise((res, rej) => {
      let el = document.createElement(type);
      // el.id = id;
      el.onload = res;
      el.error = rej;
      switch(type) {
        case 'script':
        case 'i18n':
          el.src = (type === 'i18n'? getAssetUrl('i18n') : getAssetUrl('js'))+'/'+url
          el.defer = 'defer';
          document.body.appendChild(el);
          break;
        case 'link':
          el.href = getAssetUrl('css')+'/'+url${enableRTLSplit ? `.replace(${JSON.stringify(cssDirTemplate)}, cssDir)` : ''}
          el.rel = 'stylesheet';
          document.head.appendChild(el);
          break;
      }
    });
  };

  let memorizedPromise = null;
  ${nameScope}.onload = (cb, err) => {
    if(!memorizedPromise) {
      memorizedPromise = Promise.all(
        initialAssets.map(
          (url, index) => loadAsset(
            "${nameScope}-" + (url.endsWith("js") ? "js" : "css")  +"-"+index,
            url.endsWith("js") ? url.endsWith(".i18n.js") ? "i18n" : 'script' : 'link',
            url
          )
        )
      ).then(() => ${nameScope}.onBasicLoad(cb));
    }
    return memorizedPromise;
  };

  })();
`;
  }

  apply(compiler) {
    if (!createSDkFile) {
      return;
    }

    if (this.templateFilePath) {
      new _EFCTemplatePlugin.default({
        templateFilePath: this.templateFilePath,
        publicPath: this.serverUrl,
        i18nFileNameTemplate: this.i18nFileNameTemplate,
        entryPointName: this.options.entryPointName
      }).apply(compiler);
      return;
    }

    compiler.hooks.emit.tap('EFCPlugin', compilation => {
      const {
        entryPointName,
        outputFile
      } = this.options;
      const entryPoint = compilation.entrypoints.get(entryPointName);

      if (!entryPoint) {
        return;
      }

      const source = new _webpackSources.RawSource(this.createFileContent(compilation));
      compilation.assets[outputFile] = source;
      (0, _logger.messageLogger)('The EFC embedded code was created successfully..!!!');
    });
  }

}

exports.default = EFCPlugin;