import { AsyncLocalStorage } from 'async_hooks'

export const fnStorage = new AsyncLocalStorage<{
  fns: Map<string, string>
  counter: number
}>()

export function fe<T extends Record<string, unknown>>(
  fn: (args?: T) => void,
  args?: T
): string {
  const store = fnStorage.getStore()
  if (!store) {
    // Fallback to IIFE if outside request context
    return args
      ? `(${fn.toString()})(${JSON.stringify(args)})`
      : `(${fn.toString()})()`
  }

  const fnStr = fn.toString()

  // Dedupe by function body
  for (const [name, body] of store.fns)
    if (body === fnStr)
      return args ? `${name}(${JSON.stringify(args)})` : `${name}()`

  const name = `frontendFn${store.counter++}`
  store.fns.set(name, fnStr)

  return args ? `${name}(${JSON.stringify(args)})` : `${name}()`
}

export function feFunctions(): string[] {
  const store = fnStorage.getStore()
  if (!store?.fns.size) return []

  return [...store.fns.entries()].map(([name, body]) => {
    // Handle arrow functions vs regular functions
    if (body.startsWith('(') || body.startsWith('async ('))
      return `const ${name} = ${body};`

    // Named function - rename it
    return body.replace(/^(async\s+)?function\s*\w*/, `$1function ${name}`)
  })
}

// Keep for backwards compat
export const frontend = fe