/* eslint no-param-reassign: 0 */

const puppeteer = require('puppeteer');

function snapshooter({ snapshotUrl, chrome = {} } = {}) {
  const snapshots = {};
  const images = {};
  let browser;
  let cachedPage;
  let rendering = false;

  const hasConnectOptions = chrome.browserWSEndpoint || chrome.browserURL;

  const createBrowser = () => (hasConnectOptions ? puppeteer.connect(chrome) : puppeteer.launch(chrome));

  const doIt = async (snapshot, runCached) => {
    browser = browser || (await createBrowser());
    let page;
    if (runCached) {
      cachedPage = cachedPage || (await browser.newPage());
      page = cachedPage;
    } else {
      page = await browser.newPage();
    }
    await page.setViewport({
      width: snapshot.meta.size.width,
      height: snapshot.meta.size.height,
    });
    await page.goto(`${snapshotUrl}?snapshot=${snapshot.key}`);
    try {
      await page.waitFor(
        () =>
          (document.querySelector('.njs-viz') &&
            +document.querySelector('.njs-viz').getAttribute('data-render-count') > 0) ||
          document.querySelector('[data-njs-error]')
      );
    } catch (e) {
      // empty
    }
    const image = await page.screenshot();
    images[snapshot.key] = image;
    rendering = false;
    return snapshot.key;
  };

  return {
    getStoredImage(id) {
      return images[id];
    },
    getStoredSnapshot(id) {
      return snapshots[id];
    },
    getStoredSnapshots() {
      return Object.keys(snapshots).map((key) => snapshots[key]);
    },
    storeSnapshot(snapshot) {
      if (!snapshot) {
        throw new Error('Empty snapshot');
      }
      if (!snapshot.key) {
        snapshot.key = String(+Date.now());
      }
      snapshots[snapshot.key] = snapshot;
      return snapshot.key;
    },
    async captureImageOfSnapshot(snapshot) {
      this.storeSnapshot(snapshot);
      if (rendering) {
        return doIt(snapshot);
      }
      rendering = true;
      const key = await doIt(snapshot, true);
      rendering = false;
      return key;
    },
    async close() {
      if (browser) {
        await browser.close();
      }
    },
  };
}
module.exports = snapshooter;
