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',
    };
    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();
  }

  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 console.warn('No handler for', handler || data.t, data.d);

    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) {
    this.skin.updateAttributes(skin, { 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) {
      console.warn('Content must have an id:', content);
      content.id = Widgetic.GUID();
    }

    if (!content.composition_id) {
      content.composition_id = this.composition.id;
    }
    let c = Content.refresh(content)[0];
    this.contentAdded.broadcast(c);
  }

  // FIXME UI does not update
  changeContent(content) {
    let c;
    if (content.id == null) {
      return console.error('Content must have an id:', content);
    }
    try {
      c = Content.find(content.id);
    } catch (error) {
      return console.warn(
        `Content with id ${content.id} doesn't exists, use addContent if you want to add it!`
      );
    }

    c = Content.refresh($.extend({}, c.toJSON(), content))[0];

    for (let attribute in content) {
      if (attribute === 'id') {
        continue;
      }
      c.trigger('update', c, { attribute: attribute });
      c.trigger('change', c, 'update', { attribute: attribute });
    }
  }

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