app/src/services/MessagingService.tstypescript
import { debug } from "@/utils/logging";
import i18n from "@/plugins/vue-i18n";

/**
 * Service for displaying messages and notifications to the user.
 * @class MessagingService
 */
const DEFAULT_OPTIONS = {
  modelValue: 5_000,
  solid: false,
};

interface MessageOptions {
  modelValue?: number;
  solid?: boolean;
  variant?: string;
  title?: string;
  progressProps?: Record<string, string>;
  autoHideDelay?: number;
}

class MessagingService {
  handlers: Record<
    string,
    (message: string, options: MessageOptions) => Promise<void>
  > = {};

  /**
   * Subscribe a handler for message display.
   * @param {string} key - Unique key for the handler
   * @param {Function} handler - Function to handle message display
   */
  subscribe(
    key: string,
    handler: (message: string, options: MessageOptions) => Promise<void>
  ): void {
    debug("Message handler registered", { key });
    this.handlers[key] = handler;
  }

  /**
   * Show a generic message with options.
   * @param {string} message - The message to display
   * @param {Object} options - Options for the message display
   * @returns {Promise}
   */
  _showMessage(message: string, options: MessageOptions): Promise<void[]> {
    if (options.variant) options.progressProps = { variant: options.variant };
    debug("_showMessage", { message, options });
    return Promise.all(
      Object.values(this.handlers).map((handler) =>
        handler(message, { ...DEFAULT_OPTIONS, ...options })
      )
    );
  }

  /**
   * Show an info message.
   * @param {string} message - The message to display
   * @param {string|null} title - The title of the message (optional)
   * @param {Object} [options] - Options for the message display
   * @returns {Promise}
   */
  showInfo(
    message: string,
    title: string | null = null,
    options: MessageOptions = {}
  ): Promise<void[]> {
    debug("Showing Info message", { message, title, options });
    if (!title) title = i18n.global.t("info");
    return this._showMessage(message, { title, ...options });
  }

  /**
   * Show a success message.
   * @param {string} message - The message to display
   * @param {string|null} [title] - The title of the message
   * @param {Object} [options] - Options for the message display
   * @returns {Promise}
   */
  showSuccess(
    message: string,
    title: string | null = null,
    options: MessageOptions = {}
  ): Promise<void[]> {
    debug("Showing success message", { message, title, options });
    if (!title) title = i18n.global.t("login.erfolg");
    return this._showMessage(message, {
      title,
      variant: "success",
      ...options,
    });
  }

  /**
   * Show an error message.
   * @param {string} message - The error message to display
   * @param {string|null} [title] - The title of the error message
   * @param {Object} [options] - Options for the message display
   * @returns {Promise}
   */
  showError(
    message: string,
    title: string | null = null,
    options: MessageOptions = {}
  ): Promise<void[]> {
    debug("Showing error message", { message, title, options });
    // ERROR_MESSAGES must be within this function to ensure that the right locale is used when it is called
    const ERROR_MESSAGES = [
      i18n.global.t("failMessages.oh-oh"),
      i18n.global.t("failMessages.satz-mit-x"),
      i18n.global.t("failMessages.da-dumm"),
      i18n.global.t("failMessages.check-ich-nicht"),
      i18n.global.t("failMessages.probiers-nochmal"),
      i18n.global.t("failMessages.computer-sagt-nein"),
      i18n.global.t("failMessages.traurige-trompete"),
    ];
    if (!title)
      title =
        ERROR_MESSAGES[Math.floor(Math.random() * ERROR_MESSAGES.length)]!;
    return this._showMessage(message, {
      title: title ?? undefined,
      variant: "danger",
      ...options,
    });
  }

  /**
   * Show a warning message.
   * @param {string} message - The warning message to display
   * @param {string|null} [title] - The title of the warning message
   * @param {Object} [options] - Options for the message display
   * @returns {Promise}
   */
  showWarning(
    message: string,
    title: string | null = null,
    options: MessageOptions = {}
  ): Promise<void[]> {
    debug("Showing warning message", { message, title, options });
    if (!title) title = i18n.global.t("warnung");
    return this._showMessage(message, {
      title,
      variant: "warning",
      ...options,
    });
  }
}

export default new MessagingService();