/**
 * @license
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import './gr-api-utils.js';

import {
  PLUGIN_LOADING_TIMEOUT_MS,
  PRELOADED_PROTOCOL,
  getPluginNameFromUrl,
  getBaseUrl,
} from './gr-api-utils.js';

/**
 * @enum {string}
 */
const PluginState = {
  /**
   * State that indicates the plugin is pending to be loaded.
   */
  PENDING: 'PENDING',

  /**
   * State that indicates the plugin is already loaded.
   */
  LOADED: 'LOADED',

  /**
   * State that indicates the plugin is already loaded.
   */
  PRE_LOADED: 'PRE_LOADED',

  /**
   * State that indicates the plugin failed to load.
   */
  LOAD_FAILED: 'LOAD_FAILED',
};

// Prefix for any unrecognized plugin urls.
// Url should match following patterns:
// /plugins/PLUGINNAME/static/SCRIPTNAME.(html|js)
// /plugins/PLUGINNAME.(js|html)
const UNKNOWN_PLUGIN_PREFIX = '__$$__';

// Current API version for Plugin,
// plugins with incompatible version will not be laoded.
const API_VERSION = '0.1';

/**
 * PluginLoader, responsible for:
 *
 * Loading all plugins and handling errors etc.
 * Recording plugin state.
 * Reporting on plugin loading status.
 * Retrieve plugin.
 * Check plugin status and if all plugins loaded.
 */
export class PluginLoader {
  constructor() {
    this._pluginListLoaded = false;

    /** @type {Map<string,PluginLoader.PluginObject>} */
    this._plugins = new Map();

    this._reporting = null;

    // Promise that resolves when all plugins loaded
    this._loadingPromise = null;

    // Resolver to resolve _loadingPromise once all plugins loaded
    this._loadingResolver = null;
  }

  _getReporting() {
    if (!this._reporting) {
      this._reporting = document.createElement('gr-reporting');
    }
    return this._reporting;
  }

  /**
   * Use the plugin name or use the full url if not recognized.
   *
   * @see gr-api-utils#getPluginNameFromUrl
   * @param {string|URL} url
   */
  _getPluginKeyFromUrl(url) {
    return getPluginNameFromUrl(url) ||
      `${UNKNOWN_PLUGIN_PREFIX}${url}`;
  }

  /**
   * Load multiple plugins with certain options.
   *
   * @param {Array<string>} plugins
   * @param {Object<string, PluginLoader.PluginOption>} opts
   */
  loadPlugins(plugins = [], opts = {}) {
    this._pluginListLoaded = true;

    plugins.forEach(path => {
      const url = this._urlFor(path, window.ASSETS_PATH);
      // Skip if preloaded, for bundling.
      if (this.isPluginPreloaded(url)) return;

      const pluginKey = this._getPluginKeyFromUrl(url);
      // Skip if already installed.
      if (this._plugins.has(pluginKey)) return;
      this._plugins.set(pluginKey, {
        name: pluginKey,
        url,
        state: PluginState.PENDING,
        plugin: null,
      });

      if (this._isPathEndsWith(url, '.html')) {
        this._importHtmlPlugin(path, opts && opts[path]);
      } else if (this._isPathEndsWith(url, '.js')) {
        this._loadJsPlugin(path);
      } else {
        this._failToLoad(`Unrecognized plugin path ${path}`, path);
      }
    });

    this.awaitPluginsLoaded().then(() => {
      console.info('Plugins loaded');
      this._getReporting().pluginsLoaded(this._getAllInstalledPluginNames());
    });
  }

  _isPathEndsWith(url, suffix) {
    if (!(url instanceof URL)) {
      try {
        url = new URL(url);
      } catch (e) {
        console.warn(e);
        return false;
      }
    }

    return url.pathname && url.pathname.endsWith(suffix);
  }

  _getAllInstalledPluginNames() {
    const installedPlugins = [];
    for (const plugin of this._plugins.values()) {
      if (plugin.state === PluginState.LOADED) {
        installedPlugins.push(plugin.name);
      }
    }
    return installedPlugins;
  }

  install(callback, opt_version, opt_src) {
    // HTML import polyfill adds __importElement pointing to the import tag.
    const script = document.currentScript &&
        (document.currentScript.__importElement || document.currentScript);
    let src = opt_src || (script && script.src);
    if (!src || src.startsWith('data:')) {
      src = script && script.baseURI;
    }

    if (opt_version && opt_version !== API_VERSION) {
      this._failToLoad(`Plugin ${src} install error: only version ` +
          API_VERSION + ' is supported in PolyGerrit. ' + opt_version +
          ' was given.', src);
      return;
    }

    const url = this._urlFor(src);
    const pluginObject = this.getPlugin(url);
    let plugin = pluginObject && pluginObject.plugin;
    if (!plugin) {
      plugin = new Plugin(url);
    }
    try {
      callback(plugin);
      this._pluginInstalled(url, plugin);
    } catch (e) {
      this._failToLoad(`${e.name}: ${e.message}`, src);
    }
  }

  // The polygerrit uses version of sinon where you can't stub getter,
  // declare it as a function here
  arePluginsLoaded() {
    // As the size of plugins is relatively small,
    // so the performance of this check should be reasonable
    if (!this._pluginListLoaded) return false;
    for (const plugin of this._plugins.values()) {
      if (plugin.state === PluginState.PENDING) return false;
    }
    return true;
  }

  _checkIfCompleted() {
    if (this.arePluginsLoaded() && this._loadingResolver) {
      this._loadingResolver();
      this._loadingResolver = null;
      this._loadingPromise = null;
    }
  }

  _timeout() {
    const pendingPlugins = [];
    for (const plugin of this._plugins.values()) {
      if (plugin.state === PluginState.PENDING) {
        this._updatePluginState(plugin.url, PluginState.LOAD_FAILED);
        this._checkIfCompleted();
        pendingPlugins.push(plugin.url);
      }
    }
    return `Timeout when loading plugins: ${pendingPlugins.join(',')}`;
  }

  _failToLoad(message, pluginUrl) {
    // Show an alert with the error
    document.dispatchEvent(new CustomEvent('show-alert', {
      detail: {
        message: `Plugin install error: ${message} from ${pluginUrl}`,
      },
    }));
    this._updatePluginState(pluginUrl, PluginState.LOAD_FAILED);
    this._checkIfCompleted();
  }

  _updatePluginState(pluginUrl, state) {
    const key = this._getPluginKeyFromUrl(pluginUrl);
    if (this._plugins.has(key)) {
      this._plugins.get(key).state = state;
    } else {
      // Plugin is not recorded for some reason.
      console.warn(`Plugin loaded separately: ${pluginUrl}`);
      this._plugins.set(key, {
        name: key,
        url: pluginUrl,
        state,
        plugin: null,
      });
    }
    return this._plugins.get(key);
  }

  _pluginInstalled(url, plugin) {
    const pluginObj = this._updatePluginState(url, PluginState.LOADED);
    pluginObj.plugin = plugin;
    this._getReporting().pluginLoaded(plugin.getPluginName() || url);
    console.log(`Plugin ${plugin.getPluginName() || url} installed.`);
    this._checkIfCompleted();
  }

  installPreloadedPlugins() {
    if (!window.Gerrit || !window.Gerrit._preloadedPlugins) { return; }
    const Gerrit = window.Gerrit;
    for (const name in Gerrit._preloadedPlugins) {
      if (!Gerrit._preloadedPlugins.hasOwnProperty(name)) { continue; }
      const callback = Gerrit._preloadedPlugins[name];
      this.install(callback, API_VERSION, PRELOADED_PROTOCOL + name);
    }
  }

  isPluginPreloaded(pathOrUrl) {
    const url = this._urlFor(pathOrUrl);
    const name = getPluginNameFromUrl(url);
    if (name && window.Gerrit._preloadedPlugins) {
      return window.Gerrit._preloadedPlugins.hasOwnProperty(name);
    } else {
      return false;
    }
  }

  /**
   * Checks if given plugin path/url is enabled or not.
   *
   * @param {string} pathOrUrl
   */
  isPluginEnabled(pathOrUrl) {
    const url = this._urlFor(pathOrUrl);
    if (this.isPluginPreloaded(url)) return true;
    const key = this._getPluginKeyFromUrl(url);
    return this._plugins.has(key);
  }

  /**
   * Returns the plugin object with a given url.
   *
   * @param {string} pathOrUrl
   */
  getPlugin(pathOrUrl) {
    const key = this._getPluginKeyFromUrl(this._urlFor(pathOrUrl));
    return this._plugins.get(key);
  }

  /**
   * Checks if given plugin path/url is loaded or not.
   *
   * @param {string} pathOrUrl
   */
  isPluginLoaded(pathOrUrl) {
    const url = this._urlFor(pathOrUrl);
    const key = this._getPluginKeyFromUrl(url);
    return this._plugins.has(key) ?
      this._plugins.get(key).state === PluginState.LOADED :
      false;
  }

  _importHtmlPlugin(pluginUrl, opts = {}) {
    const urlWithAP = this._urlFor(pluginUrl, window.ASSETS_PATH);
    const urlWithoutAP = this._urlFor(pluginUrl);
    let onerror = null;
    if (urlWithAP !== urlWithoutAP) {
      onerror = () => this._loadHtmlPlugin(urlWithoutAP, opts.sync);
    }
    this._loadHtmlPlugin(urlWithAP, opts.sync, onerror);
  }

  _loadHtmlPlugin(url, sync, onerror) {
    if (!onerror) {
      onerror = () => {
        this._failToLoad(`${url} import error`, url);
      };
    }

    (Polymer.importHref || Polymer.Base.importHref)(
        url, () => {},
        onerror,
        !sync);
  }

  _loadJsPlugin(pluginUrl) {
    const urlWithAP = this._urlFor(pluginUrl, window.ASSETS_PATH);
    const urlWithoutAP = this._urlFor(pluginUrl);
    let onerror = null;
    if (urlWithAP !== urlWithoutAP) {
      onerror = () => this._createScriptTag(urlWithoutAP);
    }

    this._createScriptTag(urlWithAP, onerror);
  }

  _createScriptTag(url, onerror) {
    if (!onerror) {
      onerror = () => this._failToLoad(`${url} load error`, url);
    }

    const el = document.createElement('script');
    el.defer = true;
    el.setAttribute('src', url);
    // no credentials to send when fetch plugin js
    // and this will help provide more meaningful error than
    // 'Script error.'
    el.setAttribute('crossorigin', 'anonymous');
    el.onerror = onerror;
    return document.body.appendChild(el);
  }

  _urlFor(pathOrUrl, assetsPath) {
    if (!pathOrUrl) {
      return pathOrUrl;
    }

    // theme is per host, should always load from assetsPath
    const isThemeFile = pathOrUrl.endsWith('static/gerrit-theme.html');
    const shouldTryLoadFromAssetsPathFirst = !isThemeFile && assetsPath;
    if (pathOrUrl.startsWith(PRELOADED_PROTOCOL) ||
        pathOrUrl.startsWith('http')) {
      // Plugins are loaded from another domain or preloaded.
      if (pathOrUrl.includes(location.host) &&
        shouldTryLoadFromAssetsPathFirst) {
        // if is loading from host server, try replace with cdn when assetsPath provided
        return pathOrUrl
            .replace(location.origin, assetsPath);
      }
      return pathOrUrl;
    }

    if (!pathOrUrl.startsWith('/')) {
      pathOrUrl = '/' + pathOrUrl;
    }

    if (shouldTryLoadFromAssetsPathFirst) {
      return assetsPath + pathOrUrl;
    }

    return window.location.origin + getBaseUrl() + pathOrUrl;
  }

  awaitPluginsLoaded() {
    // Resolve if completed.
    this._checkIfCompleted();

    if (this.arePluginsLoaded()) {
      return Promise.resolve();
    }
    if (!this._loadingPromise) {
      let timerId;
      this._loadingPromise =
        Promise.race([
          new Promise(resolve => this._loadingResolver = resolve),
          new Promise((_, reject) => timerId = setTimeout(
              () => {
                reject(new Error(this._timeout()));
              }, PLUGIN_LOADING_TIMEOUT_MS)),
        ]).then(() => {
          if (timerId) clearTimeout(timerId);
        });
    }
    return this._loadingPromise;
  }
}

/**
 * @typedef {{
 *            name:string,
 *            url:string,
 *            state:PluginState,
 *            plugin:Object
 *          }}
 */
PluginLoader.PluginObject;

/**
 * @typedef {{
 *            sync:boolean,
 *          }}
 */
PluginLoader.PluginOption;

// TODO(dmfilippov): Convert to service and add to appContext
export let pluginLoader = new PluginLoader();
export function _testOnly_resetPluginLoader() {
  pluginLoader = new PluginLoader();
}
