/* 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 { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { debugLocalAddon, debugRemoteAddon, isTemporaryID, parseFileUri, uninstallAddon } =
  require("../../modules/addon");
const Services = require("Services");

loader.lazyRequireGetter(this, "DebuggerClient",
  "devtools/shared/client/debugger-client", true);

const Strings = Services.strings.createBundle(
  "chrome://devtools/locale/aboutdebugging.properties");

const TEMP_ID_URL = "https://developer.mozilla.org/Add-ons" +
                    "/WebExtensions/WebExtensions_and_the_Add-on_ID";

function filePathForTarget(target) {
  // Only show file system paths, and only for temporarily installed add-ons.
  if (!target.temporarilyInstalled || !target.url || !target.url.startsWith("file://")) {
    return [];
  }
  let path = parseFileUri(target.url);
  return [
    dom.dt(
      { className: "addon-target-info-label" },
      Strings.GetStringFromName("location")),
    // Wrap the file path in a span so we can do some RTL/LTR swapping to get
    // the ellipsis on the left.
    dom.dd(
      { className: "addon-target-info-content file-path" },
      dom.span({ className: "file-path-inner", title: path }, path),
    ),
  ];
}

function addonIDforTarget(target) {
  return [
    dom.dt(
      { className: "addon-target-info-label" },
      Strings.GetStringFromName("extensionID"),
    ),
    dom.dd(
      { className: "addon-target-info-content extension-id" },
      dom.span(
        { title: target.addonID },
        target.addonID
      )
    ),
  ];
}

function internalIDForTarget(target) {
  if (!target.manifestURL) {
    return [];
  }
  // Strip off the protocol and rest, leaving us with just the UUID.
  let uuid = /moz-extension:\/\/([^/]*)/.exec(target.manifestURL)[1];
  return [
    dom.dt(
      { className: "addon-target-info-label" },
      Strings.GetStringFromName("internalUUID"),
    ),
    dom.dd(
      { className: "addon-target-info-content internal-uuid" },
      dom.span(
        { title: uuid },
        uuid
      ),
      dom.span(
        { className: "addon-target-info-more" },
        dom.a(
          { href: target.manifestURL, target: "_blank", className: "manifest-url" },
          Strings.GetStringFromName("manifestURL"),
        ),
      )
    ),
  ];
}

function showMessages(target) {
  const messages = [
    ...warningMessages(target.warnings),
    ...infoMessages(target),
  ];
  if (messages.length > 0) {
    return dom.ul(
      { className: "addon-target-messages" },
      ...messages);
  }
  return null;
}

function infoMessages(target) {
  const messages = [];
  if (isTemporaryID(target.addonID)) {
    messages.push(dom.li(
      { className: "addon-target-info-message addon-target-message" },
      Strings.GetStringFromName("temporaryID"),
      " ",
      dom.a({ href: TEMP_ID_URL, className: "temporary-id-url", target: "_blank" },
        Strings.GetStringFromName("temporaryID.learnMore")
      )));
  }
  return messages;
}

function warningMessages(warnings = []) {
  return warnings.map((warning) => {
    return dom.li(
      { className: "addon-target-warning-message addon-target-message" },
      warning);
  });
}

class AddonTarget extends Component {
  static get propTypes() {
    return {
      client: PropTypes.instanceOf(DebuggerClient).isRequired,
      connect: PropTypes.object,
      debugDisabled: PropTypes.bool,
      target: PropTypes.shape({
        addonActor: PropTypes.string.isRequired,
        addonID: PropTypes.string.isRequired,
        form: PropTypes.object.isRequired,
        icon: PropTypes.string,
        name: PropTypes.string.isRequired,
        temporarilyInstalled: PropTypes.bool,
        url: PropTypes.string,
        warnings: PropTypes.array,
      }).isRequired
    };
  }

  constructor(props) {
    super(props);
    this.debug = this.debug.bind(this);
    this.uninstall = this.uninstall.bind(this);
    this.reload = this.reload.bind(this);
  }

  debug() {
    let { client, connect, target } = this.props;

    if (connect.type === "REMOTE") {
      debugRemoteAddon(target.form, client);
    } else if (connect.type === "LOCAL") {
      debugLocalAddon(target.addonID);
    }
  }

  uninstall() {
    let { target } = this.props;
    uninstallAddon(target.addonID);
  }

  async reload() {
    let { client, target } = this.props;
    let { AboutDebugging } = window;
    try {
      await client.request({
        to: target.addonActor,
        type: "reload"
      });
      AboutDebugging.emit("addon-reload");
    } catch (e) {
      throw new Error("Error reloading addon " + target.addonID + ": " + e.message);
    }
  }

  render() {
    let { target, debugDisabled } = this.props;

    return dom.li(
      { className: "addon-target-container", "data-addon-id": target.addonID },
      dom.div({ className: "target" },
        dom.img({
          className: "target-icon",
          role: "presentation",
          src: target.icon
        }),
        dom.span(
          { className: "target-name addon-target-name", title: target.name },
          target.name)
      ),
      showMessages(target),
      dom.dl(
        { className: "addon-target-info" },
        ...filePathForTarget(target),
        ...addonIDforTarget(target),
        ...internalIDForTarget(target),
      ),
      dom.div({className: "addon-target-actions"},
        dom.button({
          className: "debug-button addon-target-button",
          onClick: this.debug,
          disabled: debugDisabled,
        }, Strings.GetStringFromName("debug")),
        target.temporarilyInstalled
          ? dom.button({
            className: "reload-button addon-target-button",
            onClick: this.reload,
          }, Strings.GetStringFromName("reload"))
          : null,
        target.temporarilyInstalled
          ? dom.button({
            className: "uninstall-button addon-target-button",
            onClick: this.uninstall,
          }, Strings.GetStringFromName("remove"))
          : null,
      ),
    );
  }
}

module.exports = AddonTarget;
