-- HousingDecorGuide/tests/test_helpers.lua
-- Minimal Lua test harness for pure-function modules.
-- Invoke via: cd HousingDecorGuide/tests && ./run_lua_tests.sh

local M = {}

local stats = { passed = 0, failed = 0, errors = {} }
local current_describe = ""

function M.describe(name, fn)
    current_describe = name
    print("\n  " .. name)
    fn()
    current_describe = ""
end

function M.it(name, fn)
    local ok, err = pcall(fn)
    if ok then
        stats.passed = stats.passed + 1
        print("    \27[32m✓\27[0m " .. name)
    else
        stats.failed = stats.failed + 1
        local label = (current_describe ~= "" and current_describe .. " > " or "") .. name
        table.insert(stats.errors, { name = label, err = err })
        print("    \27[31m✗\27[0m " .. name .. "\n        " .. tostring(err))
    end
end

function M.assert_eq(actual, expected, msg)
    if actual ~= expected then
        error((msg or "") .. " expected " .. tostring(expected) .. " got " .. tostring(actual), 2)
    end
end

function M.assert_neq(actual, unexpected, msg)
    if actual == unexpected then
        error((msg or "") .. " expected NOT " .. tostring(unexpected), 2)
    end
end

function M.assert_truthy(v, msg)
    if not v then error((msg or "") .. " expected truthy got " .. tostring(v), 2) end
end

function M.assert_falsy(v, msg)
    if v then error((msg or "") .. " expected falsy got " .. tostring(v), 2) end
end

function M.assert_nil(v, msg)
    if v ~= nil then error((msg or "") .. " expected nil got " .. tostring(v), 2) end
end

function M.assert_table_eq(actual, expected, msg)
    local seen = {}
    local function deep_eq(a, b)
        if type(a) ~= type(b) then return false end
        if type(a) ~= "table" then return a == b end
        if seen[a] and seen[a][b] then return true end   -- cycle guard
        seen[a] = seen[a] or {}; seen[a][b] = true
        for k, v in pairs(a) do if not deep_eq(v, b[k]) then return false end end
        for k, v in pairs(b) do if not deep_eq(v, a[k]) then return false end end
        return true
    end
    if not deep_eq(actual, expected) then
        error((msg or "") .. " tables not equal", 2)
    end
end

function M.run_all()
    print("\n--- " .. stats.passed .. " passed, " .. stats.failed .. " failed ---\n")
    if stats.failed > 0 then os.exit(1) end
end

return M
