import _isEqual from 'lodash/isEqual';
import _indexOf from 'lodash/indexOf';
import _without from 'lodash/without';
import { observable, action, computed, runInAction, toJS, autorun } from 'mobx';
import { client } from 'utils/ApiClient';
import { browserHistory } from 'react-router';

const DOCUMENT_PREFERENCES = 'DOCUMENT_PREFERENCES';

class DocumentSceneStore {
  @observable document;
  @observable collapsedNodes = [];

  @observable isFetching = true;
  @observable updatingContent = false;
  @observable updatingStructure = false;
  @observable isDeleting;

  /* Computed */

  @computed get isAtlas() {
    return this.document &&
      this.document.atlas.type === 'atlas';
  }

  @computed get atlasTree() {
    if (this.document.atlas.type !== 'atlas') return;
    let tree = this.document.atlas.navigationTree;

    const collapseNodes = (node) => {
      if (this.collapsedNodes.includes(node.id)) {
        node.collapsed = true;
      }
      node.children = node.children.map(childNode => {
        return collapseNodes(childNode);
      })

      return node;
    };

    return collapseNodes(toJS(tree));
  }

  /* Actions */

  @action fetchDocument = async (id, softLoad) => {
    this.isFetching = !softLoad;
    this.updatingContent = softLoad;

    try {
      const res = await client.post('/documents.info', { id: id });
      const { data } = res;
      runInAction('fetchDocument', () => {
        this.document = data;
      });
    } catch (e) {
      console.error("Something went wrong");
    }
    this.isFetching = false;
    this.updatingContent = false;
  }

  @action deleteDocument = async () => {
    this.isFetching = true;

    try {
      const res = await client.post('/documents.delete', { id: this.document.id });
      browserHistory.push(`/atlas/${this.document.atlas.id}`);
    } catch (e) {
      console.error("Something went wrong");
    }
    this.isFetching = false;
  }

  @action updateNavigationTree = async (tree) => {
    // Only update when tree changes
    if (_isEqual(toJS(tree), toJS(this.document.atlas.navigationTree))) {
      return true;
    }

    this.updatingStructure = true;

    try {
      const res = await client.post('/atlases.updateNavigationTree', {
        id: this.document.atlas.id,
        tree: tree,
      });
      runInAction('updateNavigationTree', () => {
        const { data } = res;
        this.document.atlas = data;
      });
    } catch (e) {
      console.error("Something went wrong");
    }
    this.updatingStructure = false;
  }

  @action onNodeCollapse = (nodeId, collapsed) => {
    if (_indexOf(this.collapsedNodes, nodeId) >= 0) {
      this.collapsedNodes = _without(this.collapsedNodes, nodeId);
    } else {
      this.collapsedNodes.push(nodeId);
    }
  }

  // General

  persistSettings = () => {
    localStorage[DOCUMENT_PREFERENCES] = JSON.stringify({
      collapsedNodes: toJS(this.collapsedNodes),
    });
  }

  constructor(settings) {
    // Rehydrate settings
    this.collapsedNodes = settings.collapsedNodes || [];

    // Persist settings to localStorage
    // TODO: This could be done more selectively
    autorun(() => {
      this.persistSettings();
    });
  }
};

export default DocumentSceneStore;
export {
  DOCUMENT_PREFERENCES,
};
