'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.PROCESS_SOURCE = exports.ISSUES_SOURCE = undefined;

var _map = require('babel-runtime/core-js/map');

var _map2 = _interopRequireDefault(_map);

var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

exports.default = createContext;

var _uniqBy = require('lodash/uniqBy');

var _uniqBy2 = _interopRequireDefault(_uniqBy);

var _iterall = require('iterall');

var _eventEmitterToAsyncIterator = require('../asynciterators/eventEmitterToAsyncIterator');

var _eventEmitterToAsyncIterator2 = _interopRequireDefault(_eventEmitterToAsyncIterator);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const ISSUES_SOURCE = exports.ISSUES_SOURCE = {
  __typename: 'Issues',
  id: 'Source:issues',
  name: 'Issues'
};
const PROCESS_SOURCE = exports.PROCESS_SOURCE = {
  __typename: 'Process',
  id: 'Source:metro',
  name: 'Metro Bundler'
};
const DEFAULT_SOURCES = [ISSUES_SOURCE, PROCESS_SOURCE];

function createContext({ projectDir, messageBuffer, layout, issues }) {
  return {
    getCurrentProject() {
      return {
        projectDir
      };
    },
    getMessageIterator(cursor) {
      return messageBuffer.getIterator(cursor);
    },
    getMessageEdges(source) {
      if (source) {
        if (source.id === ISSUES_SOURCE.id) {
          return issues.getIssueList();
        }
        return flattenMessagesFromBuffer(messageBuffer, source.id);
      } else {
        return flattenMessagesFromBuffer(messageBuffer);
      }
    },
    getMessageConnection(source) {
      const edges = this.getMessageEdges(source);

      let unreadCount = 0;
      let lastReadCursor = null;
      if (source) {
        var _extractReadInfo = extractReadInfo(layout.get(), source.id, edges);

        unreadCount = _extractReadInfo.unreadCount;
        lastReadCursor = _extractReadInfo.lastReadCursor;
      }

      return {
        count: edges.length,
        unreadCount,
        edges,
        // on-demand mapping
        nodes: () => edges.map(({ node }) => node),
        pageInfo: {
          hasNextPage: false,
          lastReadCursor,
          lastCursor: edges.length > 0 ? edges[edges.length - 1].cursor : null
        }
      };
    },
    getIssuesSource() {
      return ISSUES_SOURCE;
    },
    getProcessSource() {
      return PROCESS_SOURCE;
    },
    getSourceById(id) {
      const allSources = this.getSources();
      return allSources.find(source => source.id === id);
    },
    getSources() {
      const chunks = messageBuffer.all().filter(({ node }) => node && node.tag === 'device');
      const devices = (0, _uniqBy2.default)(chunks, ({ node }) => node.deviceId).map(({ node }) => ({
        __typename: 'Device',
        id: node.deviceId,
        name: node.deviceName
      }));
      return DEFAULT_SOURCES.concat(devices);
    },
    getProjectManagerLayout() {
      return layout.get();
    },
    setProjectManagerLayout(newLayout) {
      newLayout.sources.forEach(sourceId => {
        this.setLastRead(sourceId);
      });
      layout.set(newLayout);
    },
    setLastRead(sourceId, lastReadCursor) {
      if (!lastReadCursor) {
        const source = this.getSourceById(sourceId);
        const edges = this.getMessageEdges(source);
        if (edges.length === 0) {
          return;
        } else {
          lastReadCursor = edges[edges.length - 1].cursor;
        }
      }
      layout.setLastRead(sourceId, lastReadCursor.toString());
    },
    clearMessages(sourceId) {
      messageBuffer.push({
        type: 'CLEARED',
        sourceId
      });
    },
    getIssueIterator() {
      const iterator = (0, _eventEmitterToAsyncIterator2.default)(issues, ['ADDED', 'UPDATED', 'DELETED']);
      return {
        next() {
          return (0, _asyncToGenerator3.default)(function* () {
            var _ref = yield iterator.next();

            const value = _ref.value,
                  done = _ref.done;

            return {
              value: {
                type: value.eventName,
                node: value.event
              },
              done
            };
          })();
        },
        return() {
          return iterator.return();
        },
        throw(error) {
          return iterator.throw(error);
        },
        [_iterall.$$asyncIterator]() {
          return this;
        }
      };
    }
  };
}

function flattenMessagesFromBuffer(buffer, sourceId) {
  const items = buffer.allWithCursor();
  const itemsById = new _map2.default();
  const flattenedItems = [];
  for (let i = items.length - 1; i >= 0; i--) {
    var _items$i = items[i];
    const cursor = _items$i.cursor,
          item = _items$i.item;

    if (sourceId && item.sourceId !== sourceId) {
      continue;
    }
    if (item.type === 'CLEARED') {
      break;
    }
    const node = item.node;

    if (!itemsById.has(node.id)) {
      const element = { cursor, node };
      itemsById.set(node.id, element);
      flattenedItems.unshift(element);
    } else {
      itemsById.get(node.id).cursor = cursor;
    }
  }
  return flattenedItems;
}

function extractReadInfo(layout, sourceId, items) {
  let lastReadCursor = layout.sourceLastReads[sourceId];
  let unreadCount;
  if (!lastReadCursor) {
    lastReadCursor = items[0] && items[0].cursor;
    unreadCount = items.length;
  } else {
    const index = items.findIndex(({ cursor }) => cursor.toString() === lastReadCursor);
    unreadCount = items.length - index - 1;
  }
  return {
    lastReadCursor,
    unreadCount
  };
}