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

const {
  getDimcodeUserDirMock,
  mkdirMock,
  writeFileMock,
} = vi.hoisted(() => ({
  getDimcodeUserDirMock: vi.fn(),
  mkdirMock: vi.fn(),
  writeFileMock: vi.fn(),
}))

vi.mock('../src/dimsdk/cli/user-cache.ts', () => ({
  getDimcodeUserDir: getDimcodeUserDirMock,
}))

vi.mock('node:fs/promises', () => ({
  mkdir: mkdirMock,
  writeFile: writeFileMock,
}))

const { notifyUpgradeToast } = await import('../src/dimsdk/cli/upgrade-toast.ts')

afterEach(() => {
  delete (globalThis as typeof globalThis & {
    __DIMCODE_UPGRADE_TOAST__?: (text: string) => void
  }).__DIMCODE_UPGRADE_TOAST__
  getDimcodeUserDirMock.mockReset()
  mkdirMock.mockReset()
  writeFileMock.mockReset()
})

describe('cli upgrade toast', () => {
  it('uses the in-memory handler when available', async () => {
    const handler = vi.fn()
    ;(globalThis as typeof globalThis & {
      __DIMCODE_UPGRADE_TOAST__?: (text: string) => void
    }).__DIMCODE_UPGRADE_TOAST__ = handler

    notifyUpgradeToast('  Update ready  ')
    await Promise.resolve()

    expect(handler).toHaveBeenCalledWith('Update ready')
    expect(writeFileMock).not.toHaveBeenCalled()
  })

  it('persists to the toast file when no handler is installed', async () => {
    getDimcodeUserDirMock.mockResolvedValue('/tmp/dimcode')

    notifyUpgradeToast('Update available')
    await vi.waitFor(() => {
      expect(writeFileMock).toHaveBeenCalledTimes(1)
    })

    expect(getDimcodeUserDirMock).toHaveBeenCalledWith(process.env)
    expect(mkdirMock).toHaveBeenCalledWith('/tmp/dimcode', { recursive: true })
    expect(writeFileMock.mock.calls[0]?.[0]).toBe('/tmp/dimcode/upgrade-toast.json')
    expect(String(writeFileMock.mock.calls[0]?.[1] ?? '')).toContain(
      '"message":"Update available"',
    )
  })
})
