/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

/* globals global, browser, documentMetadata, util, uicontrol, ui, catcher */
/* globals domainFromUrl, randomString, shot, blobConverters */

"use strict";

this.shooter = (function () {
  // eslint-disable-line no-unused-vars
  const exports = {};
  const { AbstractShot } = shot;

  const RANDOM_STRING_LENGTH = 16;
  let backend;
  let shotObject;
  const callBackground = global.callBackground;

  function regexpEscape(str) {
    // http://stackoverflow.com/questions/3115150/how-to-escape-regular-expression-special-characters-using-javascript
    return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
  }

  function sanitizeError(data) {
    const href = new RegExp(regexpEscape(window.location.href), "g");
    const origin = new RegExp(
      `${regexpEscape(window.location.origin)}[^ \t\n\r",>]*`,
      "g"
    );
    const json = JSON.stringify(data)
      .replace(href, "REDACTED_HREF")
      .replace(origin, "REDACTED_URL");
    const result = JSON.parse(json);
    return result;
  }

  catcher.registerHandler(errorObj => {
    callBackground("reportError", sanitizeError(errorObj));
  });

  function hideUIFrame() {
    ui.iframe.hide();
    return Promise.resolve(null);
  }

  function screenshotPage(dataUrl, selectedPos, type, screenshotTaskFn) {
    let promise = Promise.resolve(dataUrl);

    if (!dataUrl) {
      promise = callBackground(
        "screenshotPage",
        selectedPos.toJSON(),
        type,
        window.devicePixelRatio
      );
    }

    catcher.watchPromise(
      promise.then(dataLoc => {
        screenshotTaskFn(dataLoc);
      })
    );
  }

  exports.downloadShot = function (selectedPos, previewDataUrl, type) {
    const shotPromise = previewDataUrl
      ? Promise.resolve(previewDataUrl)
      : hideUIFrame();
    catcher.watchPromise(
      shotPromise.then(dataUrl => {
        screenshotPage(dataUrl, selectedPos, type, url => {
          let typeFromDataUrl = blobConverters.getTypeFromDataUrl(url);
          typeFromDataUrl = typeFromDataUrl
            ? typeFromDataUrl.split("/", 2)[1]
            : null;
          shotObject.delAllClips();
          shotObject.addClip({
            createdDate: Date.now(),
            image: {
              url,
              type: typeFromDataUrl,
              location: selectedPos,
            },
          });
          ui.triggerDownload(url, shotObject.filename);
          uicontrol.deactivate();
        });
      })
    );
  };

  exports.preview = function (selectedPos, type) {
    catcher.watchPromise(
      hideUIFrame().then(dataUrl => {
        screenshotPage(dataUrl, selectedPos, type, url => {
          ui.iframe.usePreview();
          ui.Preview.display(url);
        });
      })
    );
  };

  let copyInProgress = null;
  exports.copyShot = function (selectedPos, previewDataUrl, type) {
    // This is pretty slow. We'll ignore additional user triggered copy events
    // while it is in progress.
    if (copyInProgress) {
      return;
    }
    // A max of five seconds in case some error occurs.
    copyInProgress = setTimeout(() => {
      copyInProgress = null;
    }, 5000);

    const unsetCopyInProgress = () => {
      if (copyInProgress) {
        clearTimeout(copyInProgress);
        copyInProgress = null;
      }
    };
    const shotPromise = previewDataUrl
      ? Promise.resolve(previewDataUrl)
      : hideUIFrame();
    catcher.watchPromise(
      shotPromise.then(dataUrl => {
        screenshotPage(dataUrl, selectedPos, type, url => {
          const blob = blobConverters.dataUrlToBlob(url);
          catcher.watchPromise(
            callBackground("copyShotToClipboard", blob).then(() => {
              uicontrol.deactivate();
              unsetCopyInProgress();
            }, unsetCopyInProgress)
          );
        });
      })
    );
  };

  exports.sendEvent = function (...args) {
    const maybeOptions = args[args.length - 1];

    if (typeof maybeOptions === "object") {
      maybeOptions.incognito = browser.extension.inIncognitoContext;
    } else {
      args.push({ incognito: browser.extension.inIncognitoContext });
    }
  };

  catcher.watchFunction(() => {
    shotObject = new AbstractShot(
      backend,
      randomString(RANDOM_STRING_LENGTH) + "/" + domainFromUrl(location),
      {
        origin: shot.originFromUrl(location.href),
      }
    );
    shotObject.update(documentMetadata());
  })();

  return exports;
})();
null;
