import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

// relativeTime renders a compact "Xs/Xm/Xh/Xd ago" label for freshness
// indicators (health checks, live event timestamps, etc).
export function relativeTime(iso: string | null | undefined): string {
  if (!iso) return 'never'
  const ms = Date.now() - new Date(iso).getTime()
  if (ms < 0) return 'just now'
  const s = Math.floor(ms / 1000)
  if (s < 60) return `${s}s ago`
  const m = Math.floor(s / 60)
  if (m < 60) return `${m}m ago`
  const h = Math.floor(m / 60)
  if (h < 24) return `${h}h ago`
  const d = Math.floor(h / 24)
  return `${d}d ago`
}

// Truncates long slugs/names in the middle (keeping the "type:" prefix and
// the tail visible) rather than at the end — for slugs the distinguishing
// part is often at both ends, e.g. "investigation:nomos/dragonfly-memlock-…"
// vs "…rlimit-type-8-in-unprivileged-lxcs".
export function truncateMiddle(s: string, maxLen = 36): string {
  if (s.length <= maxLen) return s
  const keep = Math.floor((maxLen - 1) / 2)
  return `${s.slice(0, keep)}…${s.slice(-keep)}`
}

// debounce wraps fn so rapid calls (e.g. keystrokes in a filter input)
// collapse into one invocation after `wait`ms of silence.
export function debounce<T extends (...args: never[]) => void>(fn: T, wait = 300): T {
  let timer: ReturnType<typeof setTimeout> | undefined
  return ((...args: Parameters<T>) => {
    clearTimeout(timer)
    timer = setTimeout(() => fn(...args), wait)
  }) as T
}

export type WithoutChild<T> = T extends { child?: unknown } ? Omit<T, 'child'> : T
export type WithoutChildren<T> = T extends { children?: unknown } ? Omit<T, 'children'> : T
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null }
