import event from 'geval/event';

let Skin;
let Composition;
let Content;

export default class EmbedApi {
  constructor() {
    Skin = window.require('core/models/skin');
    Content = window.require('core/models/content');
    Composition = window.require('core/models/composition');

    this.eventMap = {
      cx: 'clearContent',
      sc: 'setContent',
      ac: 'addContent',
      cc: 'changeContent',
      rc: 'removeContent',
      ss: 'setSkin',
      cs: 'changeSkin',
      asht: 'addSheet',
      acss: 'addCss',
      pa: 'publicApi',
    };
    this.receiver = this.receiver.bind(this);

    this.skin = Skin.first();
    this.composition = Composition.first();

    this.skinSet = new event();
    this.contentCleared = new event();
    this.contentAdded = new event();
    this.publicApiCalled = new event();
  }

  receiver(event) {
    let data;
    try {
      data = JSON.parse(event.data);
    } catch (e) {
      return console.warn(e);
    }
    const handler = this.eventMap[data.t];

    if (!handler || !this[handler]) return;

    try {
      this[handler](data.d);
    } catch (e) {
      console.error(e);
    }
  }

  /**
   * Replaces the current skin with the provided one.
   * TODO load defaults for missing props
   */
  setSkin(newSkin) {
    this.skin.unbind();
    this.skin = new Skin(newSkin);

    this.composition.updateAttribute('skin_id', this.skin.id, { ajax: false });
    this.skinSet.broadcast(this.skin);
  }

  changeSkin(skin) {
    // console.log('Embed changeSkin:', skin);
    this.skin.updateAttributes(skin, {attribute: Object.keys(skin)[0], ajax: false });
  }

  clearDemoContent() {
    return Content.select(c => c._isDemoContent).forEach(function(c) {
      try {
        c.destroy();
      } catch (error) {}
    });
  }

  clearContent() {
    Content.destroyAll();
    this.composition.updateAttribute('content', [], { ajax: false });
    this.contentCleared.broadcast();
  }

  getContent() {
    return this.composition.getContent();
  }

  setContent(data) {
    this.clearContent();
    data.map(this.addContent.bind(this));
  }

  // TODO validate limits
  addContent(content) {
    this.clearDemoContent();

    // return if thre's already added a content with the same id
    try {
      Content.find(content.id);
      return console.warn(
        `Content with id ${
          content.id
        } already exists, use changeContent if you want to update it!`
      );
    } catch (error) {}

    if (content.id == null) {
      content.id = Widgetic.GUID();
    }

    if (!content.composition_id) {
      content.composition_id = this.composition.id;
    }
    let c = new Content(content);
    c.save();
    this.contentAdded.broadcast(c);
  }

  changeContent(content) {
    let item = content.item ? content.item : content;
    let attribute = content.attribute;
    // console.log('Embed change content item:', item, attribute);

    // check if item has id 
    if (item.id == null) {
      return console.error('Content must have an id:', content);
    }

    // find the item to be changed
    let c;
    try {
      c = Content.find(item.id);
    } 
    catch (error) {
      return console.warn(
        `Content with id ${
          item.id
        } doesn't exists, use addContent if you want to add it!`
      );
    }
    
    // update the item
    c.updateAttributes(item, { attribute: attribute, ajax: false });
  }

  removeContent(content) {
    try {
      return Content.find(content.id).destroy();
    } catch (e) {
      return console.error(
        `Content ${content.id} couldn't be removed!`,
        e.stack
      );
    }
  }

  addSheet(href) {
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = href;

    document.head.appendChild(link);
  }

  addCss(css) {
    if (!this._customCssNode) {
      this._customCssNode = document.createElement('style');
      document.head.appendChild(this._customCssNode);
    }

    this._customCssNode.textContent += css;
  }

  publicApi(data) {
    this.publicApiCalled.broadcast(data);
  }
}
