/* 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/. */

/* eslint-env browser */

"use strict";

const { require } = ChromeUtils.importESModule(
  "resource://devtools/shared/loader/Loader.sys.mjs"
);

// URL constructor doesn't support about: scheme
const href = window.location.href.replace("about:", "http://");
const url = new window.URL(href);

// `host` is the frame element loading the toolbox.
let host = window.browsingContext.embedderElement;

// If there's no containerElement (which happens when loading about:devtools-toolbox as
// a top level document), use the current window.
if (!host) {
  host = {
    contentWindow: window,
    contentDocument: document,
    // toolbox-host-manager.js wants to set attributes on the frame that contains it,
    // but that is fine to skip and doesn't make sense when using the current window.
    setAttribute() {},
    ownerDocument: document,
    // toolbox-host-manager.js wants to listen for unload events from outside the frame,
    // but this is fine to skip since the toolbox code listens inside the frame as well,
    // and there is no outer document in this case.
    addEventListener() {},
  };
}

const onLoad = new Promise(r => {
  host.contentWindow.addEventListener("DOMContentLoaded", r, { once: true });
});

async function showErrorPage(doc, errorMessage) {
  const win = doc.defaultView;
  const { BrowserLoader } = ChromeUtils.import(
    "resource://devtools/shared/loader/browser-loader.js"
  );
  const browserRequire = BrowserLoader({
    window: win,
    useOnlyShared: true,
  }).require;

  const React = browserRequire("devtools/client/shared/vendor/react");
  const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
  const DebugTargetErrorPage = React.createFactory(
    require("resource://devtools/client/framework/components/DebugTargetErrorPage.js")
  );
  const { LocalizationHelper } = browserRequire("devtools/shared/l10n");
  const L10N = new LocalizationHelper(
    "devtools/client/locales/toolbox.properties"
  );

  // mount the React component into our XUL container once the DOM is ready
  await onLoad;

  // Update the tab title.
  document.title = L10N.getStr("toolbox.debugTargetInfo.tabTitleError");

  const mountEl = doc.querySelector("#toolbox-error-mount");
  const element = DebugTargetErrorPage({
    errorMessage,
    L10N,
  });
  ReactDOM.render(element, mountEl);

  // make sure we unmount the component when the page is destroyed
  win.addEventListener(
    "unload",
    () => {
      ReactDOM.unmountComponentAtNode(mountEl);
    },
    { once: true }
  );
}

async function initToolbox(url, host) {
  const {
    gDevTools,
  } = require("resource://devtools/client/framework/devtools.js");

  const {
    commandsFromURL,
  } = require("resource://devtools/client/framework/commands-from-url.js");
  const {
    Toolbox,
  } = require("resource://devtools/client/framework/toolbox.js");

  // Specify the default tool to open
  const tool = url.searchParams.get("tool");

  try {
    const commands = await commandsFromURL(url);
    const toolbox = gDevTools.getToolboxForCommands(commands);
    if (toolbox && toolbox.isDestroying()) {
      // If a toolbox already exists for the commands, wait for current
      // toolbox destroy to be finished.
      await toolbox.destroy();
    }

    // Display an error page if we are connected to a remote target and we lose it
    commands.descriptorFront.once("descriptor-destroyed", function () {
      // Prevent trying to display the error page if the toolbox tab is being destroyed
      if (host.contentDocument) {
        const error = new Error("Debug target was disconnected");
        showErrorPage(host.contentDocument, `${error}`);
      }
    });

    const options = { customIframe: host };
    await gDevTools.showToolbox(commands, {
      toolId: tool,
      hostType: Toolbox.HostType.PAGE,
      hostOptions: options,
    });
  } catch (error) {
    // When an error occurs, show error page with message.
    console.error("Exception while loading the toolbox", error);
    showErrorPage(host.contentDocument, `${error}`);
  }
}

// Only use this method to attach the toolbox if some query parameters are given
if (url.search.length > 1) {
  initToolbox(url, host);
}
// TODO: handle no params in about:devtool-toolbox
// https://bugzilla.mozilla.org/show_bug.cgi?id=1526996
