///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
//   This application incorporates Open Design Alliance software pursuant to a
//   license agreement with Open Design Alliance.
//   Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
//   All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////

function delay(ms: number, signal: AbortSignal): Promise<boolean> {
  return new Promise((resolve) => {
    let timeoutId = 0;

    const abortHandler = () => {
      clearTimeout(timeoutId);
      resolve(true);
    };

    timeoutId = window.setTimeout(() => {
      signal.removeEventListener("abort", abortHandler);
      resolve(false);
    }, ms);

    signal.addEventListener("abort", abortHandler, { once: true });
  });
}

export async function waitFor(
  func: (params: any) => Promise<boolean>,
  params: {
    timeout?: number;
    interval?: number;
    signal?: AbortSignal;
    abortError?: DOMException;
    timeoutError?: DOMException;
    result?: any;
  } = {}
): Promise<any> {
  const timeout = params.timeout || 600000;
  const interval = params.interval || 3000;
  const signal = params.signal ?? new AbortController().signal;
  const abortError = params.abortError ?? new DOMException("Aborted", "AbortError");
  const timeoutError = params.timeoutError ?? new DOMException("Timeout", "TimeoutError");

  const end = performance.now() + timeout;
  let count = timeout / interval;

  do {
    if (await func(params)) return Promise.resolve(params.result);
    if ((await delay(interval, signal)) || signal.aborted) return Promise.reject(abortError);
  } while (performance.now() < end && --count > 0);

  return Promise.reject(timeoutError);
}

export function parseArgs(args?: string | object): object {
  if (typeof args === "string") {
    const firstArg = args.indexOf("--");
    if (firstArg !== -1) args = args.slice(firstArg);
    const argArray = args
      .split("--")
      .map((x) =>
        x
          .split("=")
          .map((y) => y.split(" "))
          .flat()
      )
      .filter((x) => x[0])
      .map((x) => x.concat([""]));
    return Object.fromEntries(argArray);
  }
  return args || {};
}

export function userFullName(firstName: string | any, lastName = "", userName = ""): string {
  if (firstName && typeof firstName !== "string") {
    return userFullName(firstName.firstName ?? firstName.name, firstName.lastName, firstName.userName);
  }
  return `${firstName ?? ""} ${lastName ?? ""}`.trim() || userName;
}

export function userInitials(fullName = ""): string {
  const names = fullName.split(" ").filter((x) => x);
  return names
    .reduce((initials, name, index) => {
      if (index === 0 || index === names.length - 1) initials += name.charAt(0);
      return initials;
    }, "")
    .toUpperCase();
}
