import type { Stats } from 'node:fs'
import { afterEach, describe, expect, it, vi } from 'vitest'

const { spawnMock, statMock } = vi.hoisted(() => ({
  spawnMock: vi.fn(),
  statMock: vi.fn(),
}))

vi.mock('node:child_process', () => ({
  spawn: spawnMock,
}))

vi.mock('node:fs/promises', () => ({
  stat: statMock,
}))

const {
  openPathExternally,
  openUrlExternally,
  sanitizeExternalFilePath,
} = await import('../src/dimsdk/pages/utils/open-external.ts')

const realProcess = globalThis.process

function setProcessPlatform(platform: NodeJS.Platform): void {
  Object.defineProperty(globalThis, 'process', {
    configurable: true,
    value: {
      ...realProcess,
      platform,
    },
  })
}

function createStats(
  opts: Readonly<{ isDirectory: boolean }>,
): Stats {
  return {
    isDirectory: () => opts.isDirectory,
  } as Stats
}

afterEach(() => {
  spawnMock.mockReset()
  statMock.mockReset()
  Object.defineProperty(globalThis, 'process', {
    configurable: true,
    value: realProcess,
  })
})

describe('open external helpers', () => {
  it('rejects dangerous file paths before spawning anything', () => {
    expect(sanitizeExternalFilePath('')).toBeNull()
    expect(sanitizeExternalFilePath('/tmp/demo\nrm -rf /')).toBeNull()
    expect(sanitizeExternalFilePath('/tmp/demo;rm')).toBeNull()
    expect(sanitizeExternalFilePath('/tmp/demo.txt')).toBe('/tmp/demo.txt')
  })

  it('reveals files on macOS when the target exists as a file', async () => {
    setProcessPlatform('darwin')
    statMock.mockResolvedValue(createStats({ isDirectory: false }))
    const unref = vi.fn()
    spawnMock.mockReturnValue({ unref })

    await expect(openPathExternally('/tmp/demo.txt')).resolves.toBe(true)

    expect(spawnMock).toHaveBeenCalledWith('open', ['-R', '/tmp/demo.txt'], {
      shell: false,
      detached: true,
      stdio: 'ignore',
    })
    expect(unref).toHaveBeenCalledTimes(1)
  })

  it('opens valid urls with the platform launcher and ignores invalid ones', async () => {
    setProcessPlatform('linux')
    const unref = vi.fn()
    spawnMock.mockReturnValue({ unref })

    await expect(openUrlExternally('notaurl')).resolves.toBe(false)
    await expect(openUrlExternally('https://example.com/docs')).resolves.toBe(true)

    expect(spawnMock).toHaveBeenCalledTimes(1)
    expect(spawnMock).toHaveBeenCalledWith('xdg-open', ['https://example.com/docs'], {
      shell: false,
      detached: true,
      stdio: 'ignore',
    })
    expect(unref).toHaveBeenCalledTimes(1)
  })
})
