/**
 * Represents a MitID Integrator that provides methods for interacting with the MitID broker.
 *
 * Key concepts:
 * - Allow the client to interact with the MitID broker using a popup window.
 * - Connect to the MitID broker using the provided environment variables.
 * - Provide a callback function to handle the authentication code received from the broker.
 * - Maintain the connection to the client's windown instance and enable it to consume the data through the message event.
 *
 * Prerequisites:
 * - The client must have the environment variables for the MitID broker.
 * - The client must have a callback function to handle the authentication code.
 * - The client must have a window instance to consume the data through the message event.
 *
 * @class MitIDIntegrator
 * @constructor
 * @param {Object} env - The environment variables for the MitID broker.
 * @returns {MitIDIntegrator} - The MitIDIntegrator instance.
 *
 * @example
 * const env = {
 *  BROKER_DOMAIN: "https://mitid-broker.com",
 *  BROKER_CLIENTID: "client-id",
 *  REDIRECT_URI: "https://client.com/callback"
 * };
 * const mitIDIntegrator = new MitIDIntegrator(env);
 */
class MitIDIntegrator {
  domain: string;
  clientId: string;
  redirectUri: string;

  windowInstance: Window | undefined = undefined;

  width = 600;
  height = 700;

  top = this.windowInstance
    ? this.windowInstance.outerHeight / 2 +
      this.windowInstance.screenY -
      this.height / 2
    : 100;
  left = this.windowInstance
    ? this.windowInstance.outerWidth / 2 +
      this.windowInstance.screenX -
      this.width / 2
    : 100;

  popupConfig = {
    toolbar: "no",
    location: "no",
    directories: "no",
    status: "no",
    menubar: "no",
    scrollbars: "no",
    resizable: "no",
    copyhistory: "no",
    width: this.width,
    height: this.height,
    top: this.top,
    left: this.left,
  };

  popupWindow: Window | null = null;

  constructor(env: {
    BROKER_DOMAIN: string;
    BROKER_CLIENTID: string;
    REDIRECT_URI: string;
  }) {
    this.domain = env.BROKER_DOMAIN;
    this.clientId = env.BROKER_CLIENTID;
    this.redirectUri = env.REDIRECT_URI;
    this.windowInstance = typeof window !== "undefined" ? window : undefined;
  }

  openPopup(callback: Function) {
    const endpoint = `${this.domain}/connect/authorize`;

    const params = {
      idp_values: "mitid",
      scope: "openid mitid",
      response_type: "code",
      client_id: this.clientId,
      redirect_uri: this.redirectUri,
    };

    const queryParams = Object.entries(params)
      .map(([key, value]) => `${key}=${value}`)
      .join("&");

    const url = `${endpoint}?${queryParams}`;

    if (this.popupWindow) {
      this.popupWindow.close();
    }

    const popupParams = Object.entries(this.popupConfig)
      .map(([key, value]) => `${key}=${value}`)
      .join(",");

    this.popupWindow = this.windowInstance
      ? this.windowInstance.open(url, "login", popupParams)
      : null;

    if (this.popupWindow) {
      this.popupWindow.focus();
    }

    let authCode: string | null = null;

    this.windowInstance?.addEventListener("message", (event) => {
      if (event.source === this.popupWindow) {
        console.log("Received message from popup:", event.data);

        if (event.data.action === "Success") {
          authCode = event.data.code;
        }
        if (event.data.action === "ClosePopUp") {
          authCode && callback(authCode);
        }
      }
    });
  }
}

module.exports = MitIDIntegrator;
