import { DateTime } from "luxon"

export const currentLocalTime = () => {
  return DateTime.now().setZone(zone).toFormat("yyyy-MM-dd HH:mm:ss")
}

// Can't be a fat arrow function because of the `asserts` keyword
export function ensure(condition: unknown, message: string): asserts condition {
  if (!condition) {
    console.error(message)
    throw new Error(message)
  }
}

export const sleep = (ms: number) => {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

export const random = <T>(array: T[]): T => {
  const randomIndex = Math.floor(Math.random() * array.length)

  return array[randomIndex]!
}

// timeBomb is an assert that only goes off in development and after a certain date. It logs a warning if the condition is not met.
export const timeBomb = (date: string, message: string) => {
  if (process.env.NODE_ENV === "production") return
  const now = DateTime.now()
  const targetDate = DateTime.fromISO(date)

  if (now > targetDate) {
    const stack = new Error().stack
    console.warn(`💣 Time bomb triggered: ${message}\n${stack}`)
  }
}

export const zone = "America/Los_Angeles"

export const debounce = <T extends (...args: any[]) => void>(
  func: T,
  wait: number
): ((...args: Parameters<T>) => void) => {
  let timeout: any

  return (...args: Parameters<T>) => {
    if (timeout) clearTimeout(timeout)

    timeout = setTimeout(() => {
      func(...args)
      timeout = undefined
    }, wait)
  }
}

export function assertNever(value: never, message: string): never {
  throw new Error(`Unexpected value: ${message}`)
}
