import "server-only";

export async function delay(ms: number) {
  if (ms <= 0) {
    return;
  }

  await new Promise((resolve) => setTimeout(resolve, ms));
}

export async function withRetries<T>(
  fn: (attempt: number) => Promise<T>,
  options?: {
    retries?: number;
    initialDelayMs?: number;
    maxDelayMs?: number;
  },
) {
  const retries = options?.retries ?? 3;
  const initialDelayMs = options?.initialDelayMs ?? 500;
  const maxDelayMs = options?.maxDelayMs ?? 4000;

  let attempt = 0;
  let lastError: unknown;

  while (attempt < retries) {
    attempt += 1;

    try {
      return await fn(attempt);
    } catch (error) {
      lastError = error;

      if (attempt >= retries) {
        break;
      }

      const waitMs = Math.min(maxDelayMs, initialDelayMs * 2 ** (attempt - 1));
      await delay(waitMs);
    }
  }

  throw lastError;
}

export function normalizeUrl(rawUrl: string | null | undefined, base?: string | null) {
  if (!rawUrl) {
    return null;
  }

  try {
    if (base) {
      return new URL(rawUrl, base).toString();
    }

    return new URL(rawUrl).toString();
  } catch {
    return null;
  }
}

export function toStringArray(value: unknown) {
  if (!Array.isArray(value)) {
    return [];
  }

  return value
    .map((entry) => (typeof entry === "string" ? entry.trim() : ""))
    .filter((entry) => entry.length > 0);
}

export function toObjectArray(value: unknown) {
  if (!Array.isArray(value)) {
    return [];
  }

  return value.filter((entry) => entry && typeof entry === "object") as Record<string, unknown>[];
}
