-- RLSettingsTests.lua
-- Purpose: Data model tests for RLSettings — structure, defaults, ranges,
--          dependency chains, and getter nil-guards
-- Author: Ritter
-- Note: "dependancy" is an intentional legacy spelling from the original fork

RLSettingsTests = {}

local Log = RmLogging.getLogger("RLRM")

--- Run RLSettings data model validation tests
---@param assert function Assert closure from RLTestRunner
function RLSettingsTests:runAll(assert)
    Log:info("--- RLSettings Tests ---")

    local S = RLSettings.SETTINGS

    -- =========================================================================
    -- Group 1: Module Existence (2 assertions)
    -- =========================================================================

    assert("SETTINGS RLSettings exists", type(RLSettings) == "table", "table", type(RLSettings))
    assert("SETTINGS RLSettings.SETTINGS exists", type(S) == "table", "table", type(S))

    -- =========================================================================
    -- Group 2: Setting Counts (3 assertions)
    -- =========================================================================

    local totalCount = 0
    local nonButtonCount = 0
    local buttonCount = 0
    for _, setting in pairs(S) do
        totalCount = totalCount + 1
        if setting.ignore == true then
            buttonCount = buttonCount + 1
        else
            nonButtonCount = nonButtonCount + 1
        end
    end

    assert("SETTINGS total count == 17", totalCount == 17, 17, totalCount)
    assert("SETTINGS non-button count == 12", nonButtonCount == 12, 12, nonButtonCount)
    assert("SETTINGS button count == 5", buttonCount == 5, 5, buttonCount)

    -- =========================================================================
    -- Group 3: Non-Button Structural Validation (1 aggregated assertion)
    -- =========================================================================

    local allValid = true
    local firstFailure = nil
    for name, setting in pairs(S) do
        if setting.ignore ~= true then
            if type(setting.index) ~= "number" or setting.index < 1 then
                allValid = false
                firstFailure = name .. " bad index"
                break
            end
            if setting.type ~= "BinaryOption" and setting.type ~= "MultiTextOption" then
                allValid = false
                firstFailure = name .. " bad type"
                break
            end
            if type(setting.values) ~= "table" or #setting.values < 1 then
                allValid = false
                firstFailure = name .. " bad values"
                break
            end
            if type(setting.default) ~= "number" then
                allValid = false
                firstFailure = name .. " bad default"
                break
            end
        end
    end

    assert("SETTINGS all non-button settings have valid structure",
        allValid, "all valid", firstFailure or "all valid")

    -- =========================================================================
    -- Group 4: Button Structural Validation (1 aggregated assertion)
    -- =========================================================================

    allValid = true
    firstFailure = nil
    for name, setting in pairs(S) do
        if setting.ignore == true then
            if setting.type ~= "Button" then
                allValid = false
                firstFailure = name .. " type not Button"
                break
            end
            if type(setting.index) ~= "number" or setting.index < 1 then
                allValid = false
                firstFailure = name .. " bad index"
                break
            end
        end
    end

    assert("SETTINGS all button settings have ignore=true and type=Button",
        allValid, "all valid", firstFailure or "all valid")

    -- =========================================================================
    -- Group 5: Defaults Within Range (1 aggregated assertion)
    -- =========================================================================

    allValid = true
    firstFailure = nil
    for name, setting in pairs(S) do
        if setting.ignore ~= true then
            if setting.default < 1 or setting.default > #setting.values then
                allValid = false
                firstFailure = name .. " default=" .. setting.default .. " out of 1.." .. #setting.values
                break
            end
        end
    end

    assert("SETTINGS all non-button defaults within values range",
        allValid, "all valid", firstFailure or "all valid")

    -- =========================================================================
    -- Group 6: Runtime State Validation (1 aggregated assertion)
    -- =========================================================================

    allValid = true
    firstFailure = nil
    for name, setting in pairs(S) do
        if setting.ignore ~= true then
            if setting.state == nil then
                allValid = false
                firstFailure = name .. " state is nil (initialize not called?)"
                break
            end
            if setting.state < 1 or setting.state > #setting.values then
                allValid = false
                firstFailure = name .. " state=" .. setting.state .. " out of 1.." .. #setting.values
                break
            end
        end
    end

    assert("SETTINGS all non-button runtime states within values range",
        allValid, "all valid", firstFailure or "all valid")

    -- =========================================================================
    -- Group 7: Non-Button Index Uniqueness (1 assertion)
    -- =========================================================================

    local indexSeen = {}
    local duplicateIndex = nil
    for name, setting in pairs(S) do
        if setting.ignore ~= true then
            if indexSeen[setting.index] then
                duplicateIndex = name .. " duplicates index " .. setting.index .. " with " .. indexSeen[setting.index]
                break
            end
            indexSeen[setting.index] = name
        end
    end

    assert("SETTINGS non-button indices are unique",
        duplicateIndex == nil, "all unique", duplicateIndex or "all unique")

    -- =========================================================================
    -- Group 8: Dependency Chain Validation (6 assertions — 2 per chain)
    -- "dependancy" spelling is legacy from original fork
    -- =========================================================================

    local chains = {
        { child = "accidentsChance", parentName = "deathEnabled", parentState = 2 },
        { child = "diseasesChance", parentName = "diseasesEnabled", parentState = 2 },
        { child = "animalsXML", parentName = "useCustomAnimals", parentState = 2 },
    }

    for _, chain in ipairs(chains) do
        local dep = S[chain.child] and S[chain.child].dependancy

        -- Verify dependancy.name resolves to existing setting
        local parentExists = dep ~= nil and S[dep.name] ~= nil
        assert("SETTINGS " .. chain.child .. " dependancy.name resolves to " .. chain.parentName,
            parentExists and dep.name == chain.parentName,
            chain.parentName, dep and dep.name or "nil")

        -- Verify dependancy.state is valid index into parent's values
        local parentSetting = S[chain.parentName]
        local stateValid = dep ~= nil and type(dep.state) == "number"
            and dep.state >= 1
            and parentSetting ~= nil
            and parentSetting.values ~= nil
            and dep.state <= #parentSetting.values
        assert("SETTINGS " .. chain.child .. " dependancy.state=" .. chain.parentState .. " is valid",
            stateValid and dep.state == chain.parentState,
            chain.parentState, dep and dep.state or "nil")
    end

    -- =========================================================================
    -- Group 9: Custom Animals Getter Nil-Guards (5 assertions)
    -- Save/restore RLSettings.customAnimals for test isolation
    -- =========================================================================

    local savedCustomAnimals = RLSettings.customAnimals

    RLSettings.customAnimals = nil

    assert("SETTINGS getAnimalsXMLPath returns nil when customAnimals=nil",
        RLSettings.getAnimalsXMLPath() == nil, "nil", tostring(RLSettings.getAnimalsXMLPath()))
    assert("SETTINGS getFillTypesXMLPath returns nil when customAnimals=nil",
        RLSettings.getFillTypesXMLPath() == nil, "nil", tostring(RLSettings.getFillTypesXMLPath()))
    assert("SETTINGS getTranslationsFolderPath returns nil when customAnimals=nil",
        RLSettings.getTranslationsFolderPath() == nil, "nil", tostring(RLSettings.getTranslationsFolderPath()))
    assert("SETTINGS getAnimalsBasePath returns nil when customAnimals=nil",
        RLSettings.getAnimalsBasePath() == nil, "nil", tostring(RLSettings.getAnimalsBasePath()))
    assert("SETTINGS getOverrideVanillaAnimals returns false when customAnimals=nil",
        RLSettings.getOverrideVanillaAnimals() == false, "false", tostring(RLSettings.getOverrideVanillaAnimals()))

    RLSettings.customAnimals = savedCustomAnimals
end
