'use strict';

const PreviewManager = (() => {
  const cache = new Map([]);
  let apiLock = Promise.resolve();

  const isValidPreview = (preview) => {
    return (
      preview != null &&
      typeof preview === 'object' &&
      typeof preview.id === 'string' &&
      typeof preview.width === 'number' &&
      typeof preview.height === 'number'
    );
  };

  const updateCache = (items = []) => {
    if (!Array.isArray(items)) return [];

    items.forEach(({ id, ...props }) => {
      if (cache.has(id)) {
        const item = cache.get(id);
        item.image = props.image;
      } else {
        cache.set(id, props);
      }
    });

    return items;
  };

  const api = (action, params = {}) => {
    return (apiLock = apiLock.then(() => {
      return new Promise((resolve) => {
        instance.on('api', function apiHandler(result) {
          instance.off('api', apiHandler);
          resolve(result);
        });

        BrowserAutomationStudio_PreviewApi(action, JSON.stringify(params));
      });
    }));
  };

  const instance = Object.assign({}, mitt(), {
    isCached(id) {
      return cache.has(id);
    },

    getCached(id) {
      return cache.get(id);
    },

    async fetch(id) {
      return await api('get', { id });
    },

    async add(preview = {}) {
      if (!isValidPreview(preview)) return;
      const { id, ...props } = preview;

      if (!cache.has(id)) {
        cache.set(id, props);
      }

      await api('add', preview);
    },

    async clear(excludeIds = []) {
      const removedIds = [];

      for (const id of cache.keys()) {
        if (!excludeIds.includes(id)) {
          cache.delete(id);
          removedIds.push(id);
        }
      }

      if (!removedIds.length) return;
      return await api('removeAll', { ids: removedIds });
    },

    async request(includeIds = []) {
      const uniqueIds = [...new Set(includeIds)].filter((id) => {
        return !cache.has(id) || !cache.get(id).image;
      });
      if (!uniqueIds.length) return [];

      return updateCache(await api('getAll', { ids: uniqueIds }));
    },
  });

  api('getAll', { includeImage: false }).then((items) => {
    updateCache(items);
  });

  return instance;
})();
