
// ref: 
// https://github.com/vuejs/vue-router/blob/dev/src/index.js

import ZeroPlugin from './plugin.zero.js';
import VueRouter from 'vue-router';
import plugins from './plugins.js';
import mediaConfig from '../config/media.config.js';
import linksConfig from '../config/links.config.js';
import routerConfig from '../config/router.config.js'
import Axios from 'axios';

class Zero
{
  static install;
  static instance;

  config = { };

  _vue = null;
  _plugins = [];
  _editors = [];
  _lists = [];
  _routes = [];
  _router = null;
  _setupDone = false;


  constructor(vue, opts)
  {
    let initialConfig = JSON.parse(document.getElementById('zeroconfig').innerHTML);
    this.config = {
      ...initialConfig,
      media: mediaConfig,
      linkPicker: linksConfig,
      ...(opts || {})
    };

    console.info(this.config);

    this._vue = vue;

    this.use(ZeroPlugin);
    //this.use(CommercePlugin);
    //this.use(TestPlugin);
  }


  /*
   * Get the currently installed version of the zero frontend
   */
  get version()
  {
    return this.config.version;
  }

  /*
   * Get all installed zero plugins
   */
  get plugins()
  {
    return this._plugins;
  }


  /*
   * Get all installed zero plugins
   */
  get router()
  {
    return this._router;
  }


  /*
   * Reload config
   */
  reloadConfig(config)
  {
    return Axios.get('zerovue/config').then(res =>
    {
      this.config = {
        ...res.data,
        media: mediaConfig,
        linkPicker: linksConfig,
        ...(config || {})
      };
    });
  }


  /*
   * Locates zero plugins and install them
   */
  setup()
  {
    this._router = new VueRouter({
      ...routerConfig,
      routes: this._routes
    });

    this._router.beforeEach(routerConfig.beforeEach);

    //const result = await Axios.get('zerovue/config');
    //this.config = { ...this.config, ...result.data };

    this._setupDone = true;
    //EventHub.$emit('zero.setup');
  }


  /*
   * Installs a zero plugin by a given path
   * Each plugin is a superset of a vue (client) plugin and can therefore hook into the vue system
   */
  useByPath(pluginPath)
  {
    //const plugin = import('../../../' + pluginPath + '/plugin.js').then(res =>
    //{
    //  this.use(res.default);
    //});
  }


  /*
   * Installs a zero plugin
   * Each plugin is a superset of a vue (client) plugin and can therefore hook into the vue system
   */
  use(plugin)
  {
    if (typeof plugin.install === 'function')
    {
      plugin.install(this._vue, this);
    }

    this._plugins.push(plugin);

    // append routes
    if (this._setupDone)
    {
      this._router.addRoutes(plugin.routes);
    }
    else
    {
      plugin.routes.forEach(x => this._routes.push(x));
    }

    // append editors
    plugin.editors.forEach(x => this.addOrReplace(this._editors, x, 'alias'));

    // append lists
    plugin.lists.forEach(x => this.addOrReplace(this._lists, x, 'alias'));

    // append 

    console.log(`[zero] Installed %c${plugin.name}%cplugin`, 'font-style:italic;');
  }


  /*
   * Returns an editor renderer
   */
  getEditor(alias)
  {
    const renderer = this._editors.find(x => x.alias === alias);

    if (!renderer)
    {
      console.warn(`[zero] Could not find editor renderer ${alias}`);
    }

    return renderer;
  }


  /*
  * Returns a list renderer
  */
  getList(alias)
  {
    const renderer = this._lists.find(x => x.alias === alias);

    if (!renderer)
    {
      console.warn(`[zero] Could not find list renderer ${alias}`);
    }

    return renderer;
  }


  /*
  * Adds or replaces an item in an array by key
  */
  private addOrReplace(array, item, byKey)
  {
    const existingRenderer = array.find(x => x[byKey] === item[byKey]);

    if (existingRenderer)
    {
      const index = array.indexOf(existingRenderer);
      array.splice(index, 1, item);
    }
    else
    {
      array.push(item);
    }
  }
};


/*
 * Registers zero within the vue system
 */
Zero.install = (vue, opts) =>
{
  const zero = new Zero(vue, opts);

  Zero.instance = zero;

  Object.defineProperty(vue.prototype, 'zero', {
    get: () => zero
  });

  zero.setup();

  console.log('[zero] Setup completed');

  plugins.forEach(plugin =>
  {
    zero.use(plugin);
  });
};

export default Zero;