-- factoryos.services.registry — node/service directory + stale detection.
-- attach(node, opts) registers svc "core.registry" and returns the store.

local util  = require("factoryos.util")
local store = require("factoryos.core.store")
local sched = require("factoryos.core.sched")

local M = {}

function M.attach(node, opts)
  opts = opts or {}
  local staleAfter   = opts.staleAfter   or (node.hbInterval * 3)
  local offlineAfter = opts.offlineAfter or (node.hbInterval * 6)
  local persistEvery = opts.persistEvery or 60

  local R = {
    nodes = store.load("registry", {}),   -- uuid -> record
  }

  local function record(d)
    local rec = R.nodes[d.id] or {}
    for k, v in pairs(d) do rec[k] = v end
    rec.lastSeen = util.clock()
    rec.state = "online"
    R.nodes[d.id] = rec
    return rec
  end

  local function setState(rec, s)
    if rec.state ~= s then
      rec.state = s
      node:_emit_local("registry.change", rec)
    end
  end

  node:service("core.registry", {
    ops = {
      heartbeat = function(env)
        if type(env.p) == "table" and env.p.id then
          record(env.p)
        end
      end,
      query = function()
        return { ok = true, nodes = R.nodes }
      end,
      get = function(_, p)
        return { ok = true, node = p and p.id and R.nodes[p.id] }
      end,
    },
  })

  -- announces register nodes too, so heartbeat-less nodes still appear
  node:on("peer", function(d) if d and d.id then record(d) end end)

  -- seed self
  record(node:descriptor())

  node:spawn(function()
    local sincePersist = 0
    while true do
      sched.sleep(5)
      sincePersist = sincePersist + 5
      record(node:descriptor())  -- keep self record current (services grow)
      local now = util.clock()
      for _, rec in pairs(R.nodes) do
        if rec.id ~= node.id then
          local age = now - (rec.lastSeen or 0)
          if age > offlineAfter then setState(rec, "offline")
          elseif age > staleAfter then setState(rec, "stale") end
        end
      end
      if sincePersist >= persistEvery then
        sincePersist = 0
        store.save("registry", R.nodes)
      end
    end
  end, "registry.gc")

  return R
end

return M
