-- factoryos.services.ui — input surface for the desktop.
-- svc "core.ui" ops: nav {key}, macro {action, params}.
-- Actions are registered by the shell (desktop, apps) via M.action().

local M = {}
local actions = {}

--- Register a named macro action (consoles invoke these). fn(params)→ok,msg
function M.action(name, fn) actions[name] = fn end
function M.actions() return actions end

function M.attach(node, opts)
  local wm = opts.wm
  local log = opts.log or require("factoryos.core.log")

  node:service("core.ui", {
    ops = {
      nav = { level = "read", fn = function(_, p)
        if not (p and p.key) then return { ok = false, err = "no_key" } end
        wm:nav(p.key)
        return { ok = true }
      end },

      -- remote tap: maintenance screens and touch displaytiles send
      -- screen-space coords; the wm hit-tests like a local touch
      touch = { level = "read", fn = function(_, p)
        if not (p and p.x and p.y) then return { ok = false, err = "no_xy" } end
        wm:touch(p.x, p.y)
        return { ok = true }
      end },

      macro = { level = "operate", fn = function(_, p)
        local a = p and p.action and actions[p.action]
        if not a then return { ok = false, err = "no_such_action" } end
        local ok, res = pcall(a, p.params or {})
        log.info("macro %s → %s", p.action, tostring(res))
        return { ok = ok ~= false, result = res }
      end },
    },
  })

  -- built-in action: open an app by id
  M.action("ui.open_app", function(p)
    if opts.openApp then return opts.openApp(p and p.app) end
    return false, "no launcher"
  end)
  M.action("ui.home", function() return opts.goHome and opts.goHome() or true end)

  -- built-in action: forward a command to any service on the network.
  -- p = { svc, op, params?, to?, timeout? } — this is how consoles reach
  -- real controllers. The mainframe's own token authorizes the call.
  M.action("cmd", function(p)
    if not (p and p.svc and p.op) then return false, "need svc+op" end
    local ok, res = node:call(p.svc, p.op, p.params, {
      timeout = p.timeout or 5, to = p.to, auth = node.cfg.token,
    })
    return ok, res
  end)
end

return M
