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

const enabled = vi.fn()
vi.mock('../api', () => ({ pluginsApi: { enabled: (...args) => enabled(...args) } }))

const { loadEnabledPlugins, isPluginEnabled, resetEnabledPlugins } =
  await import('./enabledPlugins')

beforeEach(() => {
  resetEnabledPlugins()
  enabled.mockReset()
  vi.useFakeTimers()
})

afterEach(() => {
  vi.useRealTimers()
})

describe('loadEnabledPlugins', () => {
  it('resolves the enabled set and gates on it', async () => {
    enabled.mockResolvedValue({ data: { data: ['machines', 'printers'] } })

    await loadEnabledPlugins()

    expect(isPluginEnabled('machines')).toBe(true)
    expect(isPluginEnabled('usb')).toBe(false)
  })

  it('fails open on error', async () => {
    enabled.mockRejectedValue(new Error('boom'))

    await loadEnabledPlugins()

    expect(isPluginEnabled('usb')).toBe(true)
  })

  it('does not hang the router when the request never settles', async () => {
    // What an app-pool restart looks like: IIS queues the request while the
    // worker starts, and axios has no timeout.
    enabled.mockReturnValue(new Promise(() => {}))

    const pending = loadEnabledPlugins()
    await vi.advanceTimersByTimeAsync(5000)

    await expect(pending).resolves.toBeNull()
    expect(isPluginEnabled('usb')).toBe(true)
  })

  it('retries on the next navigation after a hung request', async () => {
    enabled.mockReturnValueOnce(new Promise(() => {}))

    const first = loadEnabledPlugins()
    await vi.advanceTimersByTimeAsync(5000)
    await first

    // The dead promise must not be cached, or every later navigation inherits
    // it and stays frozen even once the backend is back.
    enabled.mockResolvedValueOnce({ data: { data: ['machines'] } })
    await loadEnabledPlugins()

    expect(enabled).toHaveBeenCalledTimes(2)
    expect(isPluginEnabled('machines')).toBe(true)
    expect(isPluginEnabled('usb')).toBe(false)
  })

  it('fetches once while the request is healthy', async () => {
    enabled.mockResolvedValue({ data: { data: ['machines'] } })

    await loadEnabledPlugins()
    await loadEnabledPlugins()

    expect(enabled).toHaveBeenCalledTimes(1)
  })
})
