import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

import { installWindowGuards, restoreWindowGuardsForTest } from './installWindowGuards'

describe('installWindowGuards', () => {
  const logger = vi.fn()

  beforeEach(() => {
    logger.mockReset()
    restoreWindowGuardsForTest()
  })

  afterEach(() => {
    restoreWindowGuardsForTest()
  })

  it('blocks native dialogs and popup windows with structured logs', () => {
    installWindowGuards(logger)

    expect(window.alert('danger')).toBeUndefined()
    expect(window.confirm('continue?')).toBe(false)
    expect(window.prompt('name?', 'admin')).toBeNull()
    expect(window.open('https://example.com', '_blank')).toBeNull()

    expect(logger).toHaveBeenCalledTimes(4)
    expect(logger.mock.calls[0][0]).toContain('native-alert-blocked')
    expect(logger.mock.calls[1][0]).toContain('native-confirm-blocked')
    expect(logger.mock.calls[2][0]).toContain('native-prompt-blocked')
    expect(logger.mock.calls[3][0]).toContain('popup-blocked')
  })

  it('logs window errors and unhandled promise rejections', () => {
    installWindowGuards(logger)

    const runtimeError = new Error('boom')
    window.dispatchEvent(new ErrorEvent('error', {
      message: runtimeError.message,
      filename: '/app.js',
      lineno: 12,
      colno: 34,
      error: runtimeError,
    }))

    const rejectionEvent = new Event('unhandledrejection') as PromiseRejectionEvent
    Object.defineProperty(rejectionEvent, 'promise', {
      value: Promise.resolve(),
      configurable: true,
    })
    Object.defineProperty(rejectionEvent, 'reason', {
      value: new Error('rejected'),
      configurable: true,
    })
    window.dispatchEvent(rejectionEvent)

    expect(logger).toHaveBeenCalledTimes(2)
    expect(logger.mock.calls[0][0]).toContain('[window-guard] error')
    expect(logger.mock.calls[1][0]).toContain('[window-guard] unhandledrejection')
  })

  it('does not install twice', () => {
    installWindowGuards(logger)
    installWindowGuards(logger)

    window.alert('once')
    expect(logger).toHaveBeenCalledTimes(1)
  })
})
