-- factoryos.modules.rswitch — named redstone switch board.
-- Exposes configured outputs (computer sides and/or Advanced Peripherals
-- redstoneIntegrator ports) as switchable, toggleable, pulsable circuits.
-- With autoSides=true (default) the six computer faces are always available
-- as outputs named "top","left",... so a bare computer is a working switch.

local sdk   = require("factoryos.sdk")
local rsout = require("factoryos.drivers.redstoneout")

local SIDES = { "top", "bottom", "left", "right", "front", "back" }

return sdk.module{
  id = "factoryos.rswitch", version = "1.0.0",
  requires = {},
  failsafe = "continue",  -- hold last state on backbone loss

  init = function(ctx)
    local outputs = {}
    for k, v in pairs(ctx.cfg.outputs or {}) do outputs[k] = v end
    if ctx.cfg.autoSides ~= false then
      for _, s in ipairs(SIDES) do
        if not outputs[s] then outputs[s] = s end
      end
    end
    ctx.state.out = rsout.new(outputs)
    ctx.log.info("rswitch: %d outputs", #(rsout.list(ctx.state.out)))
  end,

  -- optional: dump every output to a known state when the backbone drops
  onLinkLost = function(ctx)
    if ctx.cfg.linkLost == "off" then
      for name in pairs(ctx.state.out.outputs) do
        rsout.set(ctx.state.out, name, false)
      end
    end
  end,

  telemetry = function(ctx)
    local states = rsout.list(ctx.state.out)
    local metrics = {
      { n = "switch.count", v = #states, u = "outputs", q = "measured" },
      { n = "switch.node", v = ctx.node.name, u = "", q = "measured" },
    }
    for _, s in ipairs(states) do
      metrics[#metrics + 1] = {
        n = "switch.out." .. s.name, v = s.state and 1 or 0,
        u = "bool", q = "measured" }
    end
    return metrics
  end,

  services = {
    ["rswitch.read"] = {
      ops = {
        list = { level = "read", fn = function(_, _p, ctx)
          return { ok = true, outputs = rsout.list(ctx.state.out),
            integrators = rsout.integrators() }
        end },
      },
    },
    ["rswitch.control"] = {
      ops = {
        set = { level = "operate", fn = function(_, p, ctx)
          local ok, obs = rsout.set(ctx.state.out, p and p.name, p and p.state)
          return { ok = ok, observed = obs, err = ok and nil or obs }
        end },
        toggle = { level = "operate", fn = function(_, p, ctx)
          local ok, obs = rsout.toggle(ctx.state.out, p and p.name)
          return { ok = ok, observed = obs, err = ok and nil or obs }
        end },
        -- momentary: on for p.seconds (default 0.5) then off
        pulse = { level = "operate", fn = function(_, p, ctx)
          local ok, err = rsout.set(ctx.state.out, p and p.name, true)
          if not ok then return { ok = false, err = err } end
          local out, name, secs = ctx.state.out, p.name, p.seconds or 0.5
          ctx.node:spawn(function()
            require("factoryos.core.sched").sleep(secs)
            rsout.set(out, name, false)
          end, "pulse")
          return { ok = true }
        end },
      },
    },
  },
}
