local M = {}

--- @generic T
--- @param val T | nil
--- @param default_val T
--- @return T
M.default = function(val, default_val)
  if val == nil then
    return default_val
  end
  return val
end

M.default_opts = {
  debug = false,
  stat_file = true,
  db_dir = vim.fs.joinpath(vim.fn.stdpath "data", "fzf-lua-frecency"),
  display_score = true,
}

--- @param level vim.log.levels
--- @param msg string
--- @param ... any
local _notify = function(level, msg, ...)
  msg = msg or ""
  msg = "[fzf-lua-frecency]: " .. msg

  local rest = ...
  vim.notify(msg:format(rest), level)
end

--- @param msg string
--- @param ... any
M.notify_error = function(msg, ...)
  _notify(vim.log.levels.ERROR, msg, ...)
end

--- @param msg string
--- @param ... any
M.notify_debug = function(msg, ...)
  _notify(vim.log.levels.DEBUG, msg, ...)
end

M.vimscript_true = 1
M.vimscript_false = 0

--- @param str string
--- @param len number
M.pad_str = function(str, len)
  if #str >= len then
    return tostring(str)
  end

  local num_spaces = len - #str
  return string.rep(" ", num_spaces) .. str
end

--- @param num number
--- @param decimals number
M.max_decimals = function(num, decimals)
  local factor = 10 ^ decimals
  return math.floor(num * factor) / factor
end

--- @param num number
--- @param decimals number
M.min_decimals = function(num, decimals)
  return string.format("%." .. decimals .. "f", num)
end

--- @param num number
--- @param decimals number
M.exact_decimals = function(num, decimals)
  return M.min_decimals(M.max_decimals(num, decimals), decimals)
end

--- @param num number
--- @param max_len number
M.fit_decimals = function(num, max_len)
  local two_decimals = M.exact_decimals(num, 2)

  if #two_decimals <= max_len then
    return two_decimals
  end

  local one_decimal = M.exact_decimals(num, 1)
  if #one_decimal <= max_len then
    return one_decimal
  end

  local no_decimals = M.exact_decimals(num, 0)
  return no_decimals
end

--- @param db_dir? string
M.get_sorted_files_path = function(db_dir)
  db_dir = M.default(db_dir, M.default_opts.db_dir)
  return vim.fs.joinpath(db_dir, "sorted-files.txt")
end

--- @param db_dir? string
M.get_dated_files_path = function(db_dir)
  db_dir = M.default(db_dir, M.default_opts.db_dir)
  return vim.fs.joinpath(db_dir, "dated-files.mpack")
end

--- @param str string
M.strip_score = function(str)
  return str:gsub("^%d+%.?%d*%s+", "")
end

-- :h vim.fn.has
-- "win32" checks for 32 and 64 bit Windows
M.IS_WINDOWS = (vim.fn.has "win32" == M.vimscript_true) and (vim.fn.has "wsl" == M.vimscript_false)

M.get_native_filepath = function(path)
  if vim.fn.exists "+shellslash" == M.vimscript_true then
    if vim.o.shellslash ~= true then
      return path:gsub([[/]], [[\]])
    end
  end
  return path
end

return M
