local M = {}
local vfn = vim.fn


-- Returns the path leading up to (and including) the given directory, based on
-- the current buffer's file path.
--
-- Example:
--
-- The buffer path is `foo/bar/baz.txt`. When calling this function with the
-- first argument set to `bar`, this function returns `foo/bar`.
function M.find_nearest_directory(directory)
  local filename = vfn.fnameescape(vfn.fnamemodify(vim.api.nvim_buf_get_name(0), ':p'))
  local relative_path = vfn.finddir(directory, filename .. ';')

  if relative_path == '' then
    return ''
  end

  return vfn.fnamemodify(relative_path, ':p')
end


--- Return a linter that wraps another Linter with a mapping function applied
--- on its parser function. This allows to modify diagnostics generated by a
--- linter.
---
--- If the mapping function returns `nil` for a diagnostic, the original
--- diagnostic is excluded.
---
--- Example, to remap the severity of a linter:
---
--- ```lua
--- local lint = require("lint")
--- lint.linters.cspell = require("lint.util").wrap(lint.linters.cspell, function(diagnostic)
---   diagnostic.severity = vim.diagnostic.severity.HINT
---   return diagnostic
--- end)
--- ```
---
---@param linter lint.Linter|fun():lint.Linter
---@param map fun(d: vim.Diagnostic): vim.Diagnostic?
---@return lint.Linter|fun():lint.Linter
function M.wrap(linter, map)
  local function _wrap(l, m)
    local result = vim.deepcopy(l)
    result.parser = function(...)
      local diagnostics = l.parser(...)
      local mapped_diagnostics = {}
      for _, d in ipairs(diagnostics) do
        local mapped = m(d)
        if mapped then
          table.insert(mapped_diagnostics, mapped)
        end
      end
      return mapped_diagnostics
    end
    return result
  end
  if type(linter) == "function" then
    return function()
      return _wrap(linter(), map)
    end
  else
    return _wrap(linter, map)
  end
end


return M
