-- Get nvm default version and use it in node_host_prog
-- and g.copilot_node_command.
--
-- This module automatically configures Neovim to use the default Node.js version
-- from NVM. It requires a working NVM installation and 'default' alias to be set,
-- and also neovim npm package to be installed.
--
-- You can install the neovim package by running:
-- npm i --global neovim
--
-- Usage:
--   require('nvm-default').setup({
--     add_to_path = true,        -- optional: add NVM bin directory to PATH
--     nvm_path = "~/.nvm",      -- optional: custom NVM installation path
--     notify_level = "info"     -- optional: notification level
--   })

local M = {}

M.name = 'nvm-default.nvim'
M.version = '0.1.0' -- x-release-please-version

-- Helper function to run a shell command
---@param cmd string Run a shell command
---@return string? Return the result of the command
local function run_command(cmd)
  local result = vim.fn.system(cmd)
  return vim.v.shell_error == 0 and result:gsub('%s+$', '') or nil
end

-- Helper function to show a notification
---@param msg string Show a message
---@param level "info"|"warn"|"error"|"trace" Notification level
local function n(msg, level)
  if msg == nil then msg = M.name .. ': No message provided' end
  if level == nil then level = 'trace' end

  local log_level = vim.log.levels.INFO

  if level == 'info' then
    log_level = vim.log.levels.INFO
  elseif level == 'warn' then
    log_level = vim.log.levels.WARN
  elseif level == 'error' then
    log_level = vim.log.levels.ERROR
  elseif level == 'trace' then
    log_level = vim.log.levels.TRACE
  end

  vim.notify(M.name .. ': ' .. msg, log_level)
end

---@class NvmDefaultOptions
---@field add_to_path boolean Add found NVM bin directory to PATH
---@field nvm_path string Where nvm installation is located
---@field notify_level number|"info"|"warn"|"error"|"trace" Notification level filter

-- Default options
---@type NvmDefaultOptions
M.defaults = {
  add_to_path = vim.g.nvm_default_add_to_path or true,
  nvm_path = vim.fn.expand(os.getenv 'NVM_DIR' or '~/.nvm'),
  notify_level = vim.g.nvm_default_notify_level or 'info',
}

-- Fetch the NVM default version or fallback to node version
---@param opts? NvmDefaultOptions Plugin options
function M.setup(opts)
  local options = vim.tbl_deep_extend('force', M.defaults, opts or {})

  local nvm_path = options.nvm_path
  local node_version = run_command(
    string.format('. %s/nvm.sh && nvm version default', nvm_path)
  ) or run_command(string.format('. %s/nvm.sh && nvm version node', nvm_path))

  if node_version and node_version:match '^v' then
    -- Set vim.g.node_host_prog and vim.g.copilot_node_command
    local current_nvm_version_path =
      string.format('%s/versions/node/%s', nvm_path, node_version)
    local current_nvm_node_bin_path =
      string.format('%s/bin', current_nvm_version_path)
    local current_nvm_node_bin =
      string.format('%s/node', current_nvm_node_bin_path)
    local neovim_node_host_bin_path =
      string.format('%s/neovim-node-host', current_nvm_node_bin_path)

    -- Collect missing files and directories errors for error output
    local missing = {}

    -- If node_dir isn't there, stop and show error
    if not vim.fn.isdirectory(current_nvm_version_path) then
      table.insert(missing, 'Node.js directory: ' .. current_nvm_version_path)
    end

    -- If node_bin isn't there, stop and show error
    if not vim.fn.filereadable(current_nvm_node_bin) then
      table.insert(missing, 'Node.js binary: ' .. current_nvm_node_bin)
    end

    if not vim.fn.filereadable(neovim_node_host_bin_path) then
      table.insert(missing, 'Neovim host binary: ' .. neovim_node_host_bin_path)
    end

    if #missing > 0 then
      n('Missing required files:\n- ' .. table.concat(missing, '\n- '), 'error')
      return
    end

    -- Add to PATH if requested. Can be turned off by setting if it messes with
    -- other tools.
    if options.add_to_path then
      vim.env.PATH = current_nvm_node_bin_path .. ':' .. vim.env.PATH
    end

    vim.g.node_host_prog = neovim_node_host_bin_path
    vim.g.copilot_node_command = current_nvm_node_bin
  else
    n('Unable to determine the Node.js version from nvm.', 'error')
  end
end

return M
