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

const lazy = {};

ChromeUtils.defineESModuleGetters(lazy, {
  AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.sys.mjs",
  ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs",
  PanelMultiView: "resource:///modules/PanelMultiView.sys.mjs",
  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
  RemoteL10n: "resource:///modules/asrouter/RemoteL10n.sys.mjs",
  SpecialMessageActions:
    "resource://messaging-system/lib/SpecialMessageActions.sys.mjs",
  UIState: "resource://services-sync/UIState.sys.mjs",
});

export const MenuMessage = {
  SOURCES: Object.freeze({
    APP_MENU: "app_menu",
    PXI_MENU: "pxi_menu",
  }),

  SHOWING_FXA_MENU_MESSAGE_ATTR: "showing-fxa-menu-message",

  async showMenuMessage(browser, message, trigger, force) {
    if (!browser) {
      return;
    }

    let win = browser.ownerGlobal;

    if (!win || lazy.PrivateBrowsingUtils.isWindowPrivate(win)) {
      return;
    }

    let source = trigger?.context?.source || message.testingTriggerContext;

    switch (source) {
      case MenuMessage.SOURCES.APP_MENU: {
        this.showAppMenuMessage(browser, message, force);
        break;
      }
      case MenuMessage.SOURCES.PXI_MENU: {
        this.showPxiMenuMessage(browser, message, force);
        break;
      }
    }
  },

  async showAppMenuMessage(browser, message, force) {
    const win = browser.ownerGlobal;
    const msgContainer = this.hideAppMenuMessage(browser);

    // This version of the browser only supports the fxa_cta version
    // of this message in the AppMenu. We also don't draw focus away from any
    // existing AppMenuNotifications.
    if (
      !message ||
      message.content.messageType !== "fxa_cta" ||
      lazy.AppMenuNotifications.activeNotification
    ) {
      return;
    }

    // Since we know this is an fxa_cta message, we know that if we're already
    // signed in, we don't want to show it in the AppMenu.
    if (lazy.UIState.get().status === lazy.UIState.STATUS_SIGNED_IN) {
      return;
    }

    win.PanelUI.mainView.setAttribute(
      MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR,
      message.id
    );

    let msgElement = await this.constructFxAMessage(
      win,
      message,
      MenuMessage.SOURCES.APP_MENU
    );

    msgElement.addEventListener("FxAMenuMessage:Close", () => {
      win.PanelUI.mainView.removeAttribute(
        MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR
      );
    });

    msgElement.addEventListener("FxAMenuMessage:SignUp", () => {
      win.PanelUI.hide();
    });

    msgContainer.appendChild(msgElement);

    if (force) {
      win.PanelUI.show();
    }
  },

  hideAppMenuMessage(browser) {
    const win = browser.ownerGlobal;
    const document = browser.ownerDocument;
    const msgContainer = lazy.PanelMultiView.getViewNode(
      document,
      "appMenu-fxa-menu-message"
    );
    msgContainer.innerHTML = "";
    win.PanelUI.mainView.removeAttribute(
      MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR
    );

    return msgContainer;
  },

  async showPxiMenuMessage(browser, message, force) {
    const win = browser.ownerGlobal;
    const { document } = win;
    const msgContainer = this.hidePxiMenuMessage(browser);

    // This version of the browser only supports the fxa_cta version
    // of this message in the PXI menu.
    if (!message || message.content.messageType !== "fxa_cta") {
      return;
    }

    // Since we know this is an fxa_cta message, we know that if we're already
    // signed in, we don't want to show it in the AppMenu.
    if (lazy.UIState.get().status === lazy.UIState.STATUS_SIGNED_IN) {
      return;
    }

    let fxaPanelView = lazy.PanelMultiView.getViewNode(document, "PanelUI-fxa");
    fxaPanelView.setAttribute(
      MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR,
      message.id
    );

    let msgElement = await this.constructFxAMessage(
      win,
      message,
      MenuMessage.SOURCES.PXI_MENU
    );

    msgElement.addEventListener("FxAMenuMessage:Close", () => {
      fxaPanelView.removeAttribute(MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR);
    });

    msgElement.addEventListener("FxAMenuMessage:SignUp", () => {
      let panelNode = fxaPanelView.closest("panel");

      if (panelNode) {
        lazy.PanelMultiView.hidePopup(panelNode);
      }
    });

    msgContainer.appendChild(msgElement);

    if (force) {
      await win.gSync.toggleAccountPanel(
        document.getElementById("fxa-toolbar-menu-button"),
        new MouseEvent("mousedown")
      );
    }
  },

  hidePxiMenuMessage(browser) {
    const document = browser.ownerDocument;
    const msgContainer = lazy.PanelMultiView.getViewNode(
      document,
      "PanelUI-fxa-menu-message"
    );
    msgContainer.innerHTML = "";
    let fxaPanelView = lazy.PanelMultiView.getViewNode(document, "PanelUI-fxa");
    fxaPanelView.removeAttribute(MenuMessage.SHOWING_FXA_MENU_MESSAGE_ATTR);
    return msgContainer;
  },

  async constructFxAMessage(win, message, source) {
    let { document, gBrowser } = win;

    win.MozXULElement.insertFTLIfNeeded("browser/newtab/asrouter.ftl");

    const msgElement = document.createElement("fxa-menu-message");
    msgElement.imageURL = message.content.imageURL;
    msgElement.buttonText = await lazy.RemoteL10n.formatLocalizableText(
      message.content.primaryActionText
    );
    msgElement.primaryText = await lazy.RemoteL10n.formatLocalizableText(
      message.content.primaryText
    );
    msgElement.secondaryText = await lazy.RemoteL10n.formatLocalizableText(
      message.content.secondaryText
    );
    msgElement.dataset.navigableWithTabOnly = "true";
    msgElement.style.setProperty(
      "--illustration-margin-block-offset",
      `${message.content.imageVerticalOffset}px`
    );

    msgElement.addEventListener("FxAMenuMessage:Close", () => {
      msgElement.remove();

      this.recordMenuMessageTelemetry("DISMISS", source, message.id);

      lazy.SpecialMessageActions.handleAction(
        message.content.closeAction,
        gBrowser.selectedBrowser
      );
    });

    msgElement.addEventListener("FxAMenuMessage:SignUp", () => {
      this.recordMenuMessageTelemetry("CLICK", source, message.id);

      // Depending on the source that showed the message, we'll want to set
      // a particular entrypoint in the data payload in the event that we're
      // opening up the FxA sign-up page.
      let clonedPrimaryAction = structuredClone(message.content.primaryAction);
      if (source === MenuMessage.SOURCES.APP_MENU) {
        clonedPrimaryAction.data.entrypoint = "fxa_app_menu";
        clonedPrimaryAction.data.extraParams.utm_content += "-app_menu";
      } else if (source === MenuMessage.SOURCES.PXI_MENU) {
        clonedPrimaryAction.data.entrypoint = "fxa_avatar_menu";
        clonedPrimaryAction.data.extraParams.utm_content += "-avatar";
      }

      lazy.SpecialMessageActions.handleAction(
        clonedPrimaryAction,
        gBrowser.selectedBrowser
      );
    });

    return msgElement;
  },

  recordMenuMessageTelemetry(event, source, messageId) {
    let ping = {
      message_id: messageId,
      event,
      source,
    };
    lazy.ASRouter.dispatchCFRAction({
      type: "MENU_MESSAGE_TELEMETRY",
      data: { action: "menu_message_user_event", ...ping },
    });
  },
};
