import { accessSync, existsSync, readdirSync, readFileSync } from 'node:fs'
import { platform } from 'node:os'
import { exec } from 'tinyexec'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import * as platformUtils from '../../../src/utils/platform'
import {
  commandExists,
  findCommandPath,
  getHomebrewCommandPaths,
  getMcpCommand,
  getPlatform,
  getRecommendedInstallMethods,
  getSystemRoot,
  getTermuxPrefix,
  getWSLDistro,
  getWSLInfo,
  isTermux,
  isWindows,
  isWSL,
  shouldUseSudoForGlobalInstall,
} from '../../../src/utils/platform'

vi.mock('node:os')
vi.mock('node:fs')
vi.mock('tinyexec')

describe('platform utilities', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    delete process.env.PREFIX
    delete process.env.TERMUX_VERSION
    delete process.env.WSL_DISTRO_NAME
  })

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

  describe('getPlatform', () => {
    it('should return "windows" for win32', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getPlatform()).toBe('windows')
    })

    it('should return "macos" for darwin', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(getPlatform()).toBe('macos')
    })

    it('should return "linux" for linux', () => {
      vi.mocked(platform).mockReturnValue('linux')
      expect(getPlatform()).toBe('linux')
    })

    it('should return "linux" for other platforms', () => {
      vi.mocked(platform).mockReturnValue('freebsd' as any)
      expect(getPlatform()).toBe('linux')
    })
  })

  describe('isTermux', () => {
    it('should return true when PREFIX contains com.termux', () => {
      process.env.PREFIX = '/data/data/com.termux/files/usr'
      expect(isTermux()).toBe(true)
    })

    it('should return true when TERMUX_VERSION is set', () => {
      process.env.TERMUX_VERSION = '0.118.0'
      expect(isTermux()).toBe(true)
    })

    it('should return true when termux directory exists', () => {
      vi.mocked(existsSync).mockReturnValue(true)
      expect(isTermux()).toBe(true)
    })

    it('should return false when not in Termux', () => {
      vi.mocked(existsSync).mockReturnValue(false)
      expect(isTermux()).toBe(false)
    })
  })

  describe('getTermuxPrefix', () => {
    it('should return PREFIX env when set', () => {
      process.env.PREFIX = '/custom/prefix'
      expect(getTermuxPrefix()).toBe('/custom/prefix')
    })

    it('should return default termux prefix when PREFIX not set', () => {
      delete process.env.PREFIX
      expect(getTermuxPrefix()).toBe('/data/data/com.termux/files/usr')
    })
  })

  describe('isWindows', () => {
    it('should return true on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(isWindows()).toBe(true)
    })

    it('should return false on non-Windows', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(isWindows()).toBe(false)
    })
  })

  describe('getMcpCommand', () => {
    it('should return cmd command for npx on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getMcpCommand('npx')).toEqual(['cmd', '/c', 'npx'])
    })

    it('should return cmd command for uvx on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getMcpCommand('uvx')).toEqual(['cmd', '/c', 'uvx'])
    })

    it('should return cmd command for uv on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getMcpCommand('uv')).toEqual(['cmd', '/c', 'uv'])
    })

    it('should return unwrapped command for node on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getMcpCommand('node')).toEqual(['node'])
    })

    it('should return unwrapped command for python on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getMcpCommand('python')).toEqual(['python'])
    })

    it('should return npx command on non-Windows (default parameter)', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(getMcpCommand()).toEqual(['npx'])
    })

    it('should return npx command on non-Windows (explicit parameter)', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(getMcpCommand('npx')).toEqual(['npx'])
    })

    it('should return uvx command on non-Windows', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(getMcpCommand('uvx')).toEqual(['uvx'])
    })

    it('should return uv command on non-Windows', () => {
      vi.mocked(platform).mockReturnValue('linux')
      expect(getMcpCommand('uv')).toEqual(['uv'])
    })

    it('should return node command on non-Windows', () => {
      vi.mocked(platform).mockReturnValue('linux')
      expect(getMcpCommand('node')).toEqual(['node'])
    })
  })

  describe('isWSL', () => {
    it('should return true when WSL_DISTRO_NAME environment variable is set', () => {
      process.env.WSL_DISTRO_NAME = 'Ubuntu'
      expect(isWSL()).toBe(true)
    })

    it('should return true when /proc/version contains Microsoft', () => {
      vi.mocked(existsSync).mockImplementation(path => path === '/proc/version')
      vi.mocked(readFileSync).mockReturnValue('Linux version 5.4.0-Microsoft-standard #1 SMP Wed Nov 23 01:01:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux')
      expect(isWSL()).toBe(true)
    })

    it('should return true when /proc/version contains WSL', () => {
      vi.mocked(existsSync).mockImplementation(path => path === '/proc/version')
      vi.mocked(readFileSync).mockReturnValue('Linux version 5.15.90.1-WSL2-standard #1 SMP Fri Jan 27 02:56:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux')
      expect(isWSL()).toBe(true)
    })

    it('should return true when /mnt/c exists (Windows mount)', () => {
      vi.mocked(existsSync).mockImplementation((path) => {
        if (path === '/proc/version')
          return false
        if (path === '/mnt/c')
          return true
        return false
      })
      expect(isWSL()).toBe(true)
    })

    it('should return false when not in WSL environment', () => {
      vi.mocked(existsSync).mockReturnValue(false)
      vi.mocked(readFileSync).mockReturnValue('Linux version 5.15.0-generic #72-Ubuntu SMP Fri Aug 5 10:38:12 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux')
      expect(isWSL()).toBe(false)
    })

    it('should handle /proc/version read errors gracefully', () => {
      vi.mocked(existsSync).mockImplementation(path => path === '/proc/version')
      vi.mocked(readFileSync).mockImplementation(() => {
        throw new Error('Permission denied')
      })
      expect(isWSL()).toBe(false)
    })
  })

  describe('getWSLDistro', () => {
    it('should return distro name from WSL_DISTRO_NAME environment variable', () => {
      process.env.WSL_DISTRO_NAME = 'Ubuntu-22.04'
      expect(getWSLDistro()).toBe('Ubuntu-22.04')
    })

    it('should return distro name from /etc/os-release when WSL_DISTRO_NAME not set', () => {
      vi.mocked(existsSync).mockImplementation(path => path === '/etc/os-release')
      vi.mocked(readFileSync).mockReturnValue(`PRETTY_NAME="Ubuntu 22.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
ID=ubuntu`)
      expect(getWSLDistro()).toBe('Ubuntu 22.04.3 LTS')
    })

    it('should return null when no distro information available', () => {
      vi.mocked(existsSync).mockReturnValue(false)
      expect(getWSLDistro()).toBe(null)
    })

    it('should handle /etc/os-release read errors gracefully', () => {
      vi.mocked(existsSync).mockImplementation(path => path === '/etc/os-release')
      vi.mocked(readFileSync).mockImplementation(() => {
        throw new Error('File not found')
      })
      expect(getWSLDistro()).toBe(null)
    })
  })

  describe('getWSLInfo', () => {
    it('should return complete WSL info when in WSL environment', () => {
      process.env.WSL_DISTRO_NAME = 'Ubuntu-22.04'
      vi.mocked(existsSync).mockImplementation((path) => {
        if (path === '/proc/version')
          return true
        if (path === '/etc/os-release')
          return true
        return false
      })
      vi.mocked(readFileSync).mockImplementation((path) => {
        if (path === '/proc/version')
          return 'Linux version 5.4.0-Microsoft-standard'
        if (path === '/etc/os-release')
          return 'PRETTY_NAME="Ubuntu 22.04.3 LTS"'
        return ''
      })

      const info = getWSLInfo()
      expect(info).toEqual({
        isWSL: true,
        distro: 'Ubuntu-22.04',
        version: 'Linux version 5.4.0-Microsoft-standard',
      })
    })

    it('should return null when not in WSL environment', () => {
      vi.mocked(existsSync).mockReturnValue(false)
      expect(getWSLInfo()).toBe(null)
    })
  })

  describe('getSystemRoot', () => {
    beforeEach(() => {
      vi.mocked(platform).mockReturnValue('win32')
      delete process.env.SYSTEMROOT
      delete process.env.SystemRoot
    })

    it('should return null on non-Windows platforms', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(getSystemRoot()).toBeNull()
    })

    it('should return forward slash format for SYSTEMROOT env var', () => {
      process.env.SYSTEMROOT = 'C:\\Windows'
      expect(getSystemRoot()).toBe('C:/Windows')
    })

    it('should return forward slash format for SystemRoot env var', () => {
      process.env.SystemRoot = 'C:\\Windows'
      expect(getSystemRoot()).toBe('C:/Windows')
    })

    it('should convert double backslashes to forward slashes', () => {
      process.env.SYSTEMROOT = 'C:\\\\Windows'
      expect(getSystemRoot()).toBe('C:/Windows')
    })

    it('should convert mixed backslashes to forward slashes', () => {
      process.env.SYSTEMROOT = 'C:\\Windows\\\\System32'
      expect(getSystemRoot()).toBe('C:/Windows/System32')
    })

    it('should use default C:/Windows when no env vars are set', () => {
      expect(getSystemRoot()).toBe('C:/Windows')
    })

    it('should handle already forward slash paths correctly', () => {
      process.env.SYSTEMROOT = 'C:/Windows'
      expect(getSystemRoot()).toBe('C:/Windows')
    })

    it('should preserve forward slashes in mixed paths', () => {
      process.env.SYSTEMROOT = 'C:/Windows\\System32'
      expect(getSystemRoot()).toBe('C:/Windows/System32')
    })

    it('should prioritize SYSTEMROOT over SystemRoot', () => {
      process.env.SystemRoot = 'D:\\Windows'
      process.env.SYSTEMROOT = 'C:\\Windows'
      expect(getSystemRoot()).toBe('C:/Windows')
    })
  })

  describe('shouldUseSudoForGlobalInstall', () => {
    let originalGetuid: typeof process.getuid | undefined
    let execPathSpy: ReturnType<typeof vi.spyOn>
    let originalHome: string | undefined

    beforeEach(() => {
      vi.mocked(accessSync).mockImplementation(() => {})
      vi.mocked(platform).mockReturnValue('linux')
      originalHome = process.env.HOME
      process.env.HOME = '/home/test'
      delete process.env.npm_config_prefix
      delete process.env.NPM_CONFIG_PREFIX
      delete process.env.PREFIX
      originalGetuid = (process as any).getuid
      ;(process as NodeJS.Process & { getuid?: () => number }).getuid = vi.fn().mockReturnValue(1000)
      execPathSpy = vi.spyOn(process, 'execPath', 'get').mockReturnValue('/usr/bin/node')
    })

    afterEach(() => {
      if (originalHome === undefined)
        delete process.env.HOME
      else
        process.env.HOME = originalHome
      if (originalGetuid)
        (process as any).getuid = originalGetuid
      else
        delete (process as any).getuid
      execPathSpy.mockRestore()
    })

    it('should return false on non-Linux platforms', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(shouldUseSudoForGlobalInstall()).toBe(false)
    })

    it('should skip sudo when prefix resides inside the home directory', () => {
      execPathSpy.mockReturnValue('/home/test/.nvm/versions/node/v20.12.0/bin/node')
      expect(shouldUseSudoForGlobalInstall()).toBe(false)
      expect(accessSync).not.toHaveBeenCalled()
    })

    it('should skip sudo when prefix is writable without being in home', () => {
      execPathSpy.mockReturnValue('/opt/node/bin/node')
      expect(shouldUseSudoForGlobalInstall()).toBe(false)
      expect(accessSync).toHaveBeenCalledWith('/opt/node', expect.any(Number))
    })

    it('should require sudo when prefix is not writable and user is non-root', () => {
      execPathSpy.mockReturnValue('/usr/bin/node')
      vi.mocked(accessSync).mockImplementation(() => {
        const err = new Error('EACCES') as NodeJS.ErrnoException
        err.code = 'EACCES'
        throw err
      })
      expect(shouldUseSudoForGlobalInstall()).toBe(true)
    })

    it('should not require sudo when user is root even if prefix is not writable', () => {
      execPathSpy.mockReturnValue('/usr/bin/node')
      vi.mocked(accessSync).mockImplementation(() => {
        const err = new Error('EACCES') as NodeJS.ErrnoException
        err.code = 'EACCES'
        throw err
      })
      ;(process as NodeJS.Process & { getuid?: () => number }).getuid = vi.fn().mockReturnValue(0)
      expect(shouldUseSudoForGlobalInstall()).toBe(false)
    })

    it('should respect npm_config_prefix when provided', () => {
      process.env.npm_config_prefix = '/home/test/.asdf/installs/nodejs/20.11.0'
      execPathSpy.mockRestore()
      expect(shouldUseSudoForGlobalInstall()).toBe(false)
    })

    it('should return false when getuid throws error', () => {
      execPathSpy.mockReturnValue('/usr/bin/node')
      vi.mocked(accessSync).mockImplementation(() => {
        const err = new Error('EACCES') as NodeJS.ErrnoException
        err.code = 'EACCES'
        throw err
      })
      ;(process as NodeJS.Process & { getuid?: () => number }).getuid = vi.fn(() => {
        throw new Error('boom')
      })

      expect(shouldUseSudoForGlobalInstall()).toBe(false)
    })
  })

  describe('commandExists', () => {
    it('should return true when which/where command succeeds', async () => {
      vi.mocked(platform).mockReturnValue('darwin')
      vi.mocked(exec).mockResolvedValue({
        exitCode: 0,
        stdout: '/usr/local/bin/claude',
        stderr: '',
      } as any)

      const result = await commandExists('claude')
      expect(result).toBe(true)
      expect(exec).toHaveBeenCalledWith('which', ['claude'])
    })

    it('should use where command on Windows', async () => {
      vi.mocked(platform).mockReturnValue('win32')
      vi.mocked(exec).mockResolvedValue({
        exitCode: 0,
        stdout: 'C:\\Program Files\\claude.exe',
        stderr: '',
      } as any)

      const result = await commandExists('claude')
      expect(result).toBe(true)
      expect(exec).toHaveBeenCalledWith('where', ['claude'])
    })

    it('should check Termux paths when in Termux environment', async () => {
      process.env.PREFIX = '/data/data/com.termux/files/usr'
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(exec).mockRejectedValue(new Error('Command not found'))
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/data/data/com.termux/files/usr/bin/claude'
      })

      const result = await commandExists('claude')
      expect(result).toBe(true)
    })

    it('should check common Linux/Mac paths as fallback', async () => {
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(exec).mockRejectedValue(new Error('Command not found'))
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/usr/local/bin/claude'
      })

      const result = await commandExists('claude')
      expect(result).toBe(true)
    })

    it('should return false when command not found anywhere', async () => {
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(exec).mockRejectedValue(new Error('Command not found'))
      vi.mocked(existsSync).mockReturnValue(false)

      const result = await commandExists('nonexistent')
      expect(result).toBe(false)
    })

    it('should handle exec errors gracefully', async () => {
      vi.mocked(platform).mockReturnValue('darwin')
      vi.mocked(exec).mockRejectedValue(new Error('Permission denied'))
      vi.mocked(existsSync).mockReturnValue(false)

      const result = await commandExists('claude')
      expect(result).toBe(false)
    })

    it('should detect commands via Termux-specific paths', async () => {
      process.env.PREFIX = '/data/data/com.termux/files/usr'
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(exec).mockRejectedValue(new Error('not found'))
      vi.mocked(existsSync).mockImplementation(path => path === '/data/data/com.termux/files/usr/bin/claude')

      const result = await commandExists('claude')

      expect(result).toBe(true)
    })
  })

  describe('getRecommendedInstallMethods', () => {
    it('should prefer Homebrew then curl for Claude Code on macOS', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(getRecommendedInstallMethods('claude-code')).toEqual(['homebrew', 'curl', 'npm'])
    })

    it('should recommend Powershell first for Claude Code on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getRecommendedInstallMethods('claude-code')).toEqual(['powershell', 'npm'])
    })

    it('should return npm only for Codex on non-mac platforms', () => {
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(existsSync).mockReturnValue(false as any)
      expect(getRecommendedInstallMethods('codex')).toEqual(['npm'])
    })
  })

  describe('wrapCommandWithSudo', () => {
    it('should wrap command with sudo when required', () => {
      vi.mocked(platform).mockReturnValue('linux')
      const originalHome = process.env.HOME
      process.env.HOME = '/home/test'
      vi.mocked(accessSync).mockImplementation(() => {
        const err = new Error('EACCES') as NodeJS.ErrnoException
        err.code = 'EACCES'
        throw err
      })
      ;(process as NodeJS.Process & { getuid?: () => number }).getuid = vi.fn(() => 1000)
      const result = platformUtils.wrapCommandWithSudo('npm', ['install'])
      expect(result).toEqual({ command: 'sudo', args: ['npm', 'install'], usedSudo: true })
      if (originalHome === undefined)
        delete process.env.HOME
      else
        process.env.HOME = originalHome
    })

    it('should leave command unchanged when sudo is not required', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      const result = platformUtils.wrapCommandWithSudo('npm', ['install'])
      expect(result).toEqual({ command: 'npm', args: ['install'], usedSudo: false })
    })
  })

  describe('getHomebrewCommandPaths', () => {
    it('should return standard Homebrew bin paths', async () => {
      vi.mocked(existsSync).mockReturnValue(false)

      const paths = await getHomebrewCommandPaths('claude')

      expect(paths).toContain('/opt/homebrew/bin/claude')
      expect(paths).toContain('/usr/local/bin/claude')
    })

    it('should include Homebrew Cellar node bin paths when they exist', async () => {
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/opt/homebrew/Cellar/node'
      })
      vi.mocked(readFileSync).mockImplementation(() => {
        throw new Error('Not a file')
      })
      // Mock readdirSync to return version directories
      ;(readdirSync as unknown as ReturnType<typeof vi.fn>).mockImplementation((path: string) => {
        if (path === '/opt/homebrew/Cellar/node')
          return ['20.0.0', '22.0.0']
        return []
      })

      const paths = await getHomebrewCommandPaths('claude')

      // Should include standard paths
      expect(paths).toContain('/opt/homebrew/bin/claude')
      expect(paths).toContain('/usr/local/bin/claude')
    })

    it('should append cellar binaries when specific versions are present', async () => {
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/opt/homebrew/Cellar/node'
          || path === '/opt/homebrew/Cellar/node/22.0.0/bin/claude'
      })
      ;(readdirSync as unknown as ReturnType<typeof vi.fn>).mockImplementation((path: string) => {
        if (path === '/opt/homebrew/Cellar/node')
          return ['22.0.0']
        return []
      })

      const paths = await getHomebrewCommandPaths('claude')

      expect(paths).toContain('/opt/homebrew/Cellar/node/22.0.0/bin/claude')
    })

    it('should include cask binaries when cask directories exist', async () => {
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/opt/homebrew/Caskroom/claude-code'
          || path === '/opt/homebrew/Caskroom/claude-code/3.0.0/claude'
      })
      ;(readdirSync as unknown as ReturnType<typeof vi.fn>).mockImplementation((path: string) => {
        if (path === '/opt/homebrew/Caskroom/claude-code')
          return ['3.0.0']
        return []
      })

      const paths = await getHomebrewCommandPaths('claude')

      expect(paths).toContain('/opt/homebrew/Caskroom/claude-code/3.0.0/claude')
    })
  })

  describe('findCommandPath', () => {
    it('should return path from which command when successful', async () => {
      vi.mocked(platform).mockReturnValue('darwin')
      vi.mocked(exec).mockResolvedValue({
        exitCode: 0,
        stdout: '/usr/local/bin/claude',
        stderr: '',
      } as any)

      const result = await findCommandPath('claude')

      expect(result).toBe('/usr/local/bin/claude')
      expect(exec).toHaveBeenCalledWith('which', ['claude'])
    })

    it('should check common paths when which fails', async () => {
      vi.mocked(platform).mockReturnValue('darwin')
      vi.mocked(exec).mockRejectedValue(new Error('not found'))
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/usr/local/bin/claude'
      })

      const result = await findCommandPath('claude')

      expect(result).toBe('/usr/local/bin/claude')
    })

    it('should return null when command is not found anywhere', async () => {
      vi.mocked(platform).mockReturnValue('darwin')
      vi.mocked(exec).mockRejectedValue(new Error('not found'))
      vi.mocked(existsSync).mockReturnValue(false)

      const result = await findCommandPath('nonexistent')

      expect(result).toBeNull()
    })

    it('should check Termux paths when in Termux environment', async () => {
      process.env.PREFIX = '/data/data/com.termux/files/usr'
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(exec).mockRejectedValue(new Error('not found'))
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/data/data/com.termux/files/usr/bin/claude'
      })

      const result = await findCommandPath('claude')

      expect(result).toBe('/data/data/com.termux/files/usr/bin/claude')
    })

    it('should return Homebrew path when command exists only there', async () => {
      vi.mocked(platform).mockReturnValue('darwin')
      vi.mocked(exec).mockRejectedValue(new Error('not found'))
      vi.mocked(existsSync).mockImplementation(path => path === '/opt/homebrew/bin/claude')

      const result = await findCommandPath('claude')

      expect(result).toBe('/opt/homebrew/bin/claude')
    })
  })

  describe('commandExists with Homebrew paths', () => {
    it('should check Homebrew paths on macOS when standard which fails', async () => {
      vi.mocked(platform).mockReturnValue('darwin')
      vi.mocked(exec).mockRejectedValue(new Error('not found'))
      vi.mocked(existsSync).mockImplementation((path) => {
        // Return true for Homebrew path
        return path === '/opt/homebrew/bin/claude'
      })

      const result = await commandExists('claude')

      expect(result).toBe(true)
    })
  })

  describe('normalizeTomlPath', () => {
    it('should convert backslashes to forward slashes', () => {
      const { normalizeTomlPath } = platformUtils
      expect(normalizeTomlPath('C:\\Windows\\System32')).toBe('C:/Windows/System32')
    })

    it('should collapse multiple backslashes', () => {
      const { normalizeTomlPath } = platformUtils
      expect(normalizeTomlPath('C:\\\\Windows\\\\System32')).toBe('C:/Windows/System32')
    })

    it('should collapse multiple forward slashes', () => {
      const { normalizeTomlPath } = platformUtils
      expect(normalizeTomlPath('C://Windows//System32')).toBe('C:/Windows/System32')
    })

    it('should handle mixed slashes', () => {
      const { normalizeTomlPath } = platformUtils
      expect(normalizeTomlPath('C:\\Windows/System32\\test')).toBe('C:/Windows/System32/test')
    })

    it('should handle already normalized paths', () => {
      const { normalizeTomlPath } = platformUtils
      expect(normalizeTomlPath('/usr/local/bin')).toBe('/usr/local/bin')
    })
  })

  describe('getRecommendedInstallMethods - comprehensive', () => {
    it('should recommend curl then npm for Claude Code on Linux', () => {
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(existsSync).mockReturnValue(false)
      expect(getRecommendedInstallMethods('claude-code')).toEqual(['curl', 'npm'])
    })

    it('should recommend curl then npm for Claude Code in WSL', () => {
      vi.mocked(platform).mockReturnValue('linux')
      process.env.WSL_DISTRO_NAME = 'Ubuntu'
      expect(getRecommendedInstallMethods('claude-code')).toEqual(['curl', 'npm'])
      delete process.env.WSL_DISTRO_NAME
    })

    it('should recommend homebrew then npm for Codex on macOS', () => {
      vi.mocked(platform).mockReturnValue('darwin')
      expect(getRecommendedInstallMethods('codex')).toEqual(['homebrew', 'npm'])
    })

    it('should recommend npm only for Codex on Windows', () => {
      vi.mocked(platform).mockReturnValue('win32')
      expect(getRecommendedInstallMethods('codex')).toEqual(['npm'])
    })

    it('should recommend npm only for Codex in WSL', () => {
      vi.mocked(platform).mockReturnValue('linux')
      process.env.WSL_DISTRO_NAME = 'Ubuntu'
      vi.mocked(existsSync).mockReturnValue(false)
      expect(getRecommendedInstallMethods('codex')).toEqual(['npm'])
      delete process.env.WSL_DISTRO_NAME
    })

    it('should default to npm for unknown code types', () => {
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(existsSync).mockReturnValue(false)
      // @ts-expect-error testing unknown type
      expect(getRecommendedInstallMethods('unknown')).toEqual(['npm'])
    })
  })

  describe('findCommandPath - additional scenarios', () => {
    it('should return first line when multiple paths returned by where', async () => {
      vi.mocked(platform).mockReturnValue('win32')
      vi.mocked(exec).mockResolvedValue({
        exitCode: 0,
        stdout: 'C:\\path\\to\\claude.exe\nC:\\another\\path\\claude.exe',
        stderr: '',
      } as any)

      const result = await findCommandPath('claude')

      expect(result).toBe('C:\\path\\to\\claude.exe')
    })

    it('should check user local bin path', async () => {
      vi.mocked(platform).mockReturnValue('linux')
      vi.mocked(exec).mockRejectedValue(new Error('not found'))
      process.env.HOME = '/home/testuser'
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/home/testuser/.local/bin/claude'
      })

      const result = await findCommandPath('claude')

      expect(result).toBe('/home/testuser/.local/bin/claude')
    })
  })

  describe('shouldUseSudoForGlobalInstall - edge cases', () => {
    let originalGetuid: typeof process.getuid | undefined

    beforeEach(() => {
      originalGetuid = (process as any).getuid
      vi.mocked(platform).mockReturnValue('linux')
    })

    afterEach(() => {
      if (originalGetuid)
        (process as any).getuid = originalGetuid
      else
        delete (process as any).getuid
    })

    it('should return false in Termux environment', () => {
      process.env.PREFIX = '/data/data/com.termux/files/usr'
      expect(shouldUseSudoForGlobalInstall()).toBe(false)
      delete process.env.PREFIX
    })

    it('should return false when getuid is not a function', () => {
      delete (process as any).getuid
      vi.mocked(accessSync).mockImplementation(() => {
        const err = new Error('EACCES') as NodeJS.ErrnoException
        err.code = 'EACCES'
        throw err
      })

      expect(shouldUseSudoForGlobalInstall()).toBe(false)
    })
  })

  describe('getWSLInfo - edge cases', () => {
    it('should handle /proc/version read errors and return partial info', () => {
      process.env.WSL_DISTRO_NAME = 'Ubuntu'
      vi.mocked(existsSync).mockImplementation((path) => {
        return path === '/proc/version'
      })
      vi.mocked(readFileSync).mockImplementation(() => {
        throw new Error('Permission denied')
      })

      const info = getWSLInfo()

      expect(info).toEqual({
        isWSL: true,
        distro: 'Ubuntu',
        version: null,
      })
    })
  })
})
