local fs = require("filesystem")

local lib = {}

local rules_path = "/etc/udev/rules.d/"
local auto_rules = "autogenerated.lua"

local function fs_key(dir, filename)
  local long_name = dir .. '/' .. filename
  local segments = fs.segments(long_name)
  local result = '/' .. table.concat(segments, '/')
  return result
end

function lib.loadRules(root_dir)
  checkArg(1, root_dir, "string", "nil")
  root_dir = (root_dir or rules_path)
  lib.rules = {}
  lib.rules[fs_key(root_dir, auto_rules)] = {}

  for file in fs.list(root_dir) do
    if file:match("%.lua$") then
      local path = fs_key(root_dir, file)
      local file_handle = io.open(path)
      if file_handle then
        local load_rule = load("return {" .. file_handle:read("*a") .. "}")
        file_handle:close()
        if load_rule then
          local ok, rule = pcall(load_rule)
          if ok and type(rule) == "table" then
            local irule = {}
            lib.rules[path] = irule
            for _,v in ipairs(rule) do
              if type(v) == "table" then
                table.insert(irule, v)
              end
              -- else invalid rule
            end
          end
        end
      end
    end
  end
end

function lib.saveRule(rule_set, path)
  checkArg(1, rule_set, "table")
  checkArg(2, path, "string")
  local file = io.open(path, "w")
  if not file then return end -- fs may be read only, totally fine, this just won't persist
  for index, irule in ipairs(rule_set) do
    file:write(require("serialization").serialize(irule), ",\n")
  end
  file:close()
end

function lib.saveRules(rules)
  for path, rule_set in pairs(rules) do
    lib.saveRule(rule_set, path)
  end
end

local function getIRule(proxy)
  checkArg(1, proxy, "table")
  for path,rule_set in pairs(lib.rules) do
    for index, irule in ipairs(rule_set) do
      if irule.address == proxy.address then
        return irule, index, rule_set, path
      end
    end
  end
end

function lib.getDeviceLabel(proxy)
  local irule = getIRule(proxy)
  if irule and irule.label then
    return irule.label
  elseif proxy.getLabel then
    return proxy.getLabel()
  end
end

function lib.setDeviceLabel(proxy, label)
  local irule, index, rule_set, path = getIRule(proxy)
  if not irule then
    -- if the device supports labels, use it instead
    if proxy.setLabel then
      return proxy.setLabel(label)
    end
    path = fs_key(rules_path, auto_rules)
    rule_set = lib.rules[path]
    index = #rule_set + 1
    irule = {address=proxy.address}
    table.insert(rule_set, irule)
  end
  irule.label = label
  lib.saveRule(rule_set, path)
end

return lib

