/**
 * Structured logger with request context support.
 * Uses AsyncLocalStorage to provide request-scoped context that's automatically isolated per async context.
 */

import { AsyncLocalStorage } from 'node:async_hooks'

const asyncLocalStorage = new AsyncLocalStorage()

/**
 * Run a function with logger context. Context is automatically isolated per async execution.
 * @param {string} reqId - Request ID
 * @param {string|null} uId - User ID (optional)
 * @param {Function} fn - Function to run with context
 * @returns {Promise<any>} Result of the function
 */
export function runWithContext(reqId, uId, fn) {
  return asyncLocalStorage.run({ requestId: reqId, userId: uId }, fn)
}

/**
 * Set context for the current async context. Use runWithContext() instead for proper isolation.
 * @deprecated Use runWithContext() instead for proper async context isolation
 * @param {string} reqId - Request ID
 * @param {string|null} uId - User ID (optional)
 */
export function setContext(reqId, uId = null) {
  const store = asyncLocalStorage.getStore()
  if (store) {
    store.requestId = reqId
    store.userId = uId
  }
}

/**
 * Clear context for the current async context.
 * @deprecated Context is automatically cleared when async context ends. Use runWithContext() instead.
 */
export function clearContext() {
  const store = asyncLocalStorage.getStore()
  if (store) {
    store.requestId = null
    store.userId = null
  }
}

function getContext() {
  return asyncLocalStorage.getStore() || { requestId: null, userId: null }
}

function formatMessage(level, message, context = {}) {
  const { requestId, userId } = getContext()
  const timestamp = new Date().toISOString()
  const ctx = {
    timestamp,
    level,
    requestId,
    ...(userId && { userId }),
    ...context,
  }
  return `[${level.toUpperCase()}] ${JSON.stringify({ message, ...ctx })}`
}

export function info(message, context = {}) {
  console.log(formatMessage('info', message, context))
}

export function error(message, context = {}) {
  const ctx = { ...context }
  if (context.error && context.error.stack) {
    ctx.stack = context.error.stack
  }
  console.error(formatMessage('error', message, ctx))
}

export function warn(message, context = {}) {
  console.warn(formatMessage('warn', message, context))
}

export function debug(message, context = {}) {
  if (process.env.NODE_ENV === 'development') {
    console.debug(formatMessage('debug', message, context))
  }
}
