-- Shared test fakes for the trapos-cloud Lua client.
--
-- Lives under tests/harness/ so runtest.lua does NOT auto-discover it as a test
-- (discoverTests skips subdirectories), while /tests is still mounted so it can
-- be required at /tests/harness/fake-eventloop.

local M = {};

function M.fakeOs(id, label)
  return {
    getComputerID = function() return id; end,
    getComputerLabel = function() return label; end,
  };
end

-- Fake eventloop: captures registered handlers and scheduled timeouts, and lets
-- tests fire them manually to drive the daemon state machine.
function M.fakeEventloop()
  local handlers = {};
  local timers = {};
  local fake = { handlers = handlers, timers = timers };

  function fake.register(name, fn)
    handlers[name] = handlers[name] or {};
    handlers[name][#handlers[name] + 1] = fn;
    return function() end;
  end

  function fake.setTimeout(fn, seconds)
    timers[#timers + 1] = { fn = fn, seconds = seconds };
    return function() end;
  end

  function fake.fire(name, ...)
    local list = handlers[name];
    if not list then return; end
    for _, fn in ipairs(list) do
      fn(...);
    end
  end

  function fake.fireTimer(index)
    index = index or #timers;
    local t = timers[index];
    if t then t.fn(); end
  end

  return fake;
end

-- Fake websocket: records sent frames (raw strings) and close calls.
function M.fakeWs()
  local ws = { sent = {}, closed = false };
  function ws.send(text) ws.sent[#ws.sent + 1] = text; end
  function ws.close() ws.closed = true; end
  return ws;
end

-- Fake http: records websocketAsync target URLs.
function M.fakeHttp()
  local h = { connects = {} };
  function h.websocketAsync(url) h.connects[#h.connects + 1] = url; end
  function h.websocket() return nil; end
  return h;
end

-- Scriptable event primitives for request() tests. `scriptedPulls` is an ordered
-- list of packed events ({ n=?, name, p1, ... }) returned by pullEvent in turn.
function M.fakeEvents(scriptedPulls)
  local idx = 0;
  local api = { queued = {}, timers = {}, cancelled = {} };

  function api.queueEvent(name, ...)
    api.queued[#api.queued + 1] = table.pack(name, ...);
  end

  function api.startTimer(seconds)
    api.timers[#api.timers + 1] = seconds;
    return 'timer-' .. #api.timers;
  end

  function api.cancelTimer(id)
    api.cancelled[#api.cancelled + 1] = id;
  end

  function api.pullEvent()
    idx = idx + 1;
    local e = scriptedPulls[idx];
    if not e then
      error('fakeEvents: no more scripted events', 0);
    end
    return table.unpack(e, 1, e.n or #e);
  end

  return api;
end

return M;
