const UNITS = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]
const K8S_UNITS = ["B", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"]

export function niceBytes(x: string, isK8sUnits = false): string {
  const n = Number.parseInt(x, 10) || 0
  return formatBytes(n, isK8sUnits)
}

export function formatBytes(n: number, isK8sUnits = false): string {
  const l = Math.floor(Math.log(n) / Math.log(1024)) || 0

  if (l < 0) {
    return "0 B"
  }
  const value = n / 1024 ** l
  return `${value.toFixed(1)} ${isK8sUnits ? K8S_UNITS[l] : UNITS[l]}`
}

function getRuntimeLocale() {
  if (typeof document !== "undefined") {
    return document.documentElement.lang || undefined
  }

  return undefined
}

export function formatInteger(value?: number | null, fallback = "--"): string {
  if (typeof value !== "number" || !Number.isFinite(value)) return fallback

  return new Intl.NumberFormat(getRuntimeLocale(), { maximumFractionDigits: 0 }).format(value)
}

export function formatDateTime(value?: string | number | Date | null, fallback = "--"): string {
  if (!value) return fallback

  const date = value instanceof Date ? value : new Date(value)
  if (Number.isNaN(date.getTime())) return String(value)

  return new Intl.DateTimeFormat(getRuntimeLocale(), {
    dateStyle: "medium",
    timeStyle: "medium",
  }).format(date)
}

export function getBytes(value: string, unit: string, fromK8s = false): string {
  return convertToBytes(value, unit, fromK8s).toString(10)
}

function convertToBytes(value: string, unit: string, fromK8s = false): number {
  const vl = Number.parseFloat(value)
  const unitsTake = fromK8s ? K8S_UNITS : UNITS
  const powFactor = unitsTake.findIndex((element) => element === unit)

  if (powFactor === -1) {
    return 0
  }

  return vl * 1024 ** powFactor
}

export function makeRandomString(length = 20): string {
  const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
  if (length <= 0) return ""

  const cryptoApi = globalThis.crypto
  if (!cryptoApi?.getRandomValues) {
    throw new Error("Secure random generator is not available")
  }

  const result: string[] = []
  const alphabetLength = alphabet.length
  const maxByte = 256 - (256 % alphabetLength)

  while (result.length < length) {
    const bytes = cryptoApi.getRandomValues(new Uint8Array(length))
    for (const byte of bytes) {
      if (byte >= maxByte) continue
      result.push(alphabet[byte % alphabetLength] ?? "")
      if (result.length === length) break
    }
  }

  return result.join("")
}

export function randomUUID(): string {
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
    return crypto.randomUUID()
  }

  // Fallback to crypto.getRandomValues if available
  if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
    return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c: string) => {
      const n = Number.parseInt(c, 10)
      return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16)
    })
  }

  // Last resort fallback
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
    const r = (Math.random() * 16) | 0
    const v = c === "x" ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}
