-- factoryos.modules.power — facility power module.
-- Telemetry: aggregates all discovered energy_storage units, derives a net
-- rate from deltas. Control: named redstone outputs (breakers/switches).

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

return sdk.module{
  id = "factoryos.power", version = "1.0.0",
  requires = {},
  failsafe = "continue",   -- keep sampling & switching if backbone drops

  init = function(ctx)
    ctx.state.units = energy.discover()
    ctx.state.out = rsout.new(ctx.cfg.outputs or {})
    ctx.state.prev = nil
    ctx.log.info("power: discovered %d energy unit(s)", #ctx.state.units)
  end,

  telemetry = function(ctx)
    local s = energy.sample(ctx.state.units)
    local stored, cap, unitsOk = 0, 0, 0
    for _, u in ipairs(s.units) do
      stored = stored + (u.stored or 0)
      cap = cap + (u.cap or 0)
      if u.ok then unitsOk = unitsOk + 1 end
    end

    local metrics = {
      { n = "power.stored",   v = stored, u = "FE",
        q = unitsOk > 0 and "measured" or "unavailable" },
      { n = "power.capacity", v = cap, u = "FE",
        q = unitsOk > 0 and "measured" or "unavailable" },
      { n = "power.units",    v = unitsOk, u = "count", q = "measured" },
      { n = "power.node",     v = ctx.node.name, u = "", q = "measured" },
      { n = "power.units_table", v = s.units, u = "", q = "measured" },
    }
    metrics[#metrics + 1] = {
      n = "power.pct",
      v = cap > 0 and (stored / cap * 100) or 0,
      u = "%", q = cap > 0 and "measured" or "unavailable",
    }

    -- derived rate: Δstored/Δt (FE per tick; 20 ticks/s)
    local prev = ctx.state.prev
    ctx.state.prev = { stored = stored, ts = os.clock() }
    if prev and unitsOk > 0 then
      local dt = os.clock() - prev.ts
      if dt > 0 then
        metrics[#metrics + 1] = {
          n = "power.net_rate",
          v = (stored - prev.stored) / dt / 20,
          u = "FE", q = "derived",
        }
      end
    else
      metrics[#metrics + 1] = { n = "power.net_rate", v = 0, u = "FE",
        q = "unavailable" }
    end
    return metrics
  end,

  services = {
    ["power.read"] = {
      ops = {
        query = { level = "read", fn = function(_, _p, ctx)
          return { ok = true, units = ctx.state.units }
        end },
      },
    },
    ["power.control"] = {
      ops = {
        -- p = { name, state } → drive a configured redstone output
        set_output = { level = "operate", fn = function(_, p, ctx)
          local ok, observed = rsout.set(ctx.state.out, p and p.name, p and p.state)
          return { ok = ok, observed = observed, err = ok and nil or observed }
        end },
        -- admin-level placeholder for a hard isolator
        isolate = { level = "admin", danger = true, fn = function(_, p, ctx)
          local ok, observed = rsout.set(ctx.state.out, p and p.name or "isolator", false)
          return { ok = ok, observed = observed }
        end },
      },
    },
  },
}
