type GuardLogger = (message?: unknown, ...optionalParams: unknown[]) => void

type WindowGuardOriginals = {
  alert: typeof window.alert
  confirm: typeof window.confirm
  prompt: typeof window.prompt
  open: typeof window.open
}

type WindowGuardListeners = {
  error: (event: ErrorEvent) => void
  unhandledrejection: (event: PromiseRejectionEvent) => void
}

declare global {
  interface Window {
    __UMS_WINDOW_GUARDS_INSTALLED__?: boolean
    __UMS_WINDOW_GUARDS_ORIGINALS__?: WindowGuardOriginals
    __UMS_WINDOW_GUARDS_LISTENERS__?: WindowGuardListeners
  }
}

function formatValue(value: unknown): string {
  if (typeof value === 'string') {
    return value
  }

  if (value instanceof Error) {
    return value.stack || value.message
  }

  try {
    return JSON.stringify(value)
  } catch {
    return String(value)
  }
}

function reportWindowEvent(
  logger: GuardLogger,
  category: string,
  payload: Record<string, unknown>,
) {
  logger(`[window-guard] ${category}`, payload)
}

export function installWindowGuards(logger: GuardLogger = console.error) {
  if (typeof window === 'undefined' || window.__UMS_WINDOW_GUARDS_INSTALLED__) {
    return
  }

  window.__UMS_WINDOW_GUARDS_ORIGINALS__ = {
    alert: window.alert.bind(window),
    confirm: window.confirm.bind(window),
    prompt: window.prompt.bind(window),
    open: window.open.bind(window),
  }

  const onError = (event: ErrorEvent) => {
    reportWindowEvent(logger, 'error', {
      message: event.message,
      source: event.filename,
      line: event.lineno,
      column: event.colno,
      error: formatValue(event.error),
    })
  }

  const onUnhandledRejection = (event: PromiseRejectionEvent) => {
    reportWindowEvent(logger, 'unhandledrejection', {
      reason: formatValue(event.reason),
    })
  }

  window.__UMS_WINDOW_GUARDS_LISTENERS__ = {
    error: onError,
    unhandledrejection: onUnhandledRejection,
  }

  window.addEventListener('error', onError)
  window.addEventListener('unhandledrejection', onUnhandledRejection)

  window.alert = (message?: unknown) => {
    reportWindowEvent(logger, 'native-alert-blocked', {
      message: formatValue(message),
    })
  }

  window.confirm = (message?: string) => {
    reportWindowEvent(logger, 'native-confirm-blocked', {
      message: formatValue(message),
      fallback: false,
    })
    return false
  }

  window.prompt = (message?: string, defaultValue?: string) => {
    reportWindowEvent(logger, 'native-prompt-blocked', {
      message: formatValue(message),
      defaultValue: formatValue(defaultValue ?? ''),
      fallback: null,
    })
    return null
  }

  window.open = (url?: string | URL, target?: string, features?: string) => {
    reportWindowEvent(logger, 'popup-blocked', {
      url: typeof url === 'string' ? url : url?.toString() ?? '',
      target: target ?? '',
      features: features ?? '',
      fallback: null,
    })
    return null
  }

  window.__UMS_WINDOW_GUARDS_INSTALLED__ = true
}

export function restoreWindowGuardsForTest() {
  if (typeof window === 'undefined') {
    return
  }

  const originals = window.__UMS_WINDOW_GUARDS_ORIGINALS__
  const listeners = window.__UMS_WINDOW_GUARDS_LISTENERS__
  if (!originals) {
    window.__UMS_WINDOW_GUARDS_INSTALLED__ = false
    return
  }

  if (listeners) {
    window.removeEventListener('error', listeners.error)
    window.removeEventListener('unhandledrejection', listeners.unhandledrejection)
    delete window.__UMS_WINDOW_GUARDS_LISTENERS__
  }

  window.alert = originals.alert
  window.confirm = originals.confirm
  window.prompt = originals.prompt
  window.open = originals.open

  delete window.__UMS_WINDOW_GUARDS_ORIGINALS__
  window.__UMS_WINDOW_GUARDS_INSTALLED__ = false
}
