-- RLAnimalFactoryTests.lua
-- Purpose: Smoke tests for RLTestUtils test animal factory (RLRM-59)
-- Author: Ritter
-- Validates: createTestAnimal(), cleanupTestAnimals(), createMockClusterSystem(),
--            resolveSubTypeForType(), per-type defaults, deterministic genetics

RLAnimalFactoryTests = {}

local Log = RmLogging.getLogger("RLRM")

--- Run all animal factory smoke tests.
--- Tests factory methods, overrides, boundary cases, and cleanup.
--- @param assert function Assert closure from RLTestRunner
function RLAnimalFactoryTests:runAll(assert)
    Log:info("--- Animal Factory Tests ---")

    -- =========================================================================
    -- SubType Resolution
    -- =========================================================================

    local ANIMAL_TYPES = { "COW", "PIG", "SHEEP", "CHICKEN", "HORSE" }

    for _, typeName in ipairs(ANIMAL_TYPES) do
        local idx = RLTestUtils:resolveSubTypeForType(typeName)
        assert("resolveSubTypeForType returns valid index for " .. typeName,
            idx ~= nil and idx > 0, ">0", tostring(idx))
    end

    -- =========================================================================
    -- Basic Factory — COW defaults
    -- =========================================================================

    -- Clean slate before factory tests
    RLTestUtils:cleanupTestAnimals()

    local cow = RLTestUtils:createTestAnimal("COW")
    assert("createTestAnimal COW returns valid animal", cow ~= nil, "non-nil", tostring(cow))

    if cow ~= nil then
        -- Test prefix
        assert("createTestAnimal sets test prefix uniqueId",
            string.startsWith(cow.uniqueId, RLTestUtils.TEST_PREFIX),
            RLTestUtils.TEST_PREFIX .. "*", cow.uniqueId)

        -- Default values
        assert("createTestAnimal COW default age", cow.age == 24, 24, cow.age)
        assert("createTestAnimal COW default health", cow.health == 80, 80, cow.health)
        assert("createTestAnimal COW default gender", cow.gender == "female", "female", cow.gender)

        -- Deterministic genetics
        assert("createTestAnimal uses deterministic genetics (health)",
            cow.genetics.health == 1.0, 1.0, cow.genetics.health)
        assert("createTestAnimal uses deterministic genetics (fertility)",
            cow.genetics.fertility == 1.0, 1.0, cow.genetics.fertility)

        -- Registry insertion
        local cs = RLTestUtils:getSharedMockClusterSystem()
        local found = false
        for _, a in ipairs(cs.animals) do
            if a == cow then found = true end
        end
        assert("createTestAnimal inserts into clusterSystem", found, true, found)

        -- Deterministic name
        assert("createTestAnimal COW default name", cow.name == "TestCOW", "TestCOW", cow.name)
    end

    -- =========================================================================
    -- Overrides
    -- =========================================================================

    local overridden = RLTestUtils:createTestAnimal("COW", {
        age = 5, health = 50, gender = "male", name = "Brutus"
    })
    if overridden ~= nil then
        assert("createTestAnimal applies age override", overridden.age == 5, 5, overridden.age)
        assert("createTestAnimal applies health override", overridden.health == 50, 50, overridden.health)
        assert("createTestAnimal applies gender override", overridden.gender == "male", "male", overridden.gender)
        assert("createTestAnimal applies name override", overridden.name == "Brutus", "Brutus", overridden.name)
    end

    -- =========================================================================
    -- Multiple animals share clusterSystem
    -- =========================================================================

    local cs = RLTestUtils:getSharedMockClusterSystem()
    -- cow + overridden = 2 animals already in cs
    assert("multiple animals share clusterSystem",
        #cs.animals >= 2, ">=2", #cs.animals)

    -- =========================================================================
    -- Distinct uniqueIds
    -- =========================================================================

    if cow ~= nil and overridden ~= nil then
        assert("two animals get distinct uniqueIds",
            cow.uniqueId ~= overridden.uniqueId, "different", cow.uniqueId .. " vs " .. overridden.uniqueId)
    end

    -- =========================================================================
    -- Boundary: age=0 (newborn) — validates nil-safe override
    -- =========================================================================

    local newborn = RLTestUtils:createTestAnimal("COW", { age = 0 })
    if newborn ~= nil then
        assert("override age=0 produces newborn", newborn.age == 0, 0, newborn.age)
    end

    -- =========================================================================
    -- Boundary: health=0 (zero-health) — validates nil-safe override
    -- =========================================================================

    local dying = RLTestUtils:createTestAnimal("COW", { health = 0 })
    if dying ~= nil then
        assert("override health=0 produces zero-health animal", dying.health == 0, 0, dying.health)
    end

    -- =========================================================================
    -- Cleanup
    -- =========================================================================

    RLTestUtils:cleanupTestAnimals()

    -- Verify cleanup cleared animals
    -- Note: cs reference now has empty .animals after cleanup
    assert("cleanupTestAnimals removes all animals", #cs.animals == 0, 0, #cs.animals)

    -- Verify counter reset — next animal gets rl_test_1 again
    local afterCleanup = RLTestUtils:createTestAnimal("COW")
    if afterCleanup ~= nil then
        assert("cleanupTestAnimals resets counter",
            afterCleanup.uniqueId == RLTestUtils.TEST_PREFIX .. "1",
            RLTestUtils.TEST_PREFIX .. "1", afterCleanup.uniqueId)
    end

    -- =========================================================================
    -- All types create successfully
    -- =========================================================================

    RLTestUtils:cleanupTestAnimals()
    for _, typeName in ipairs(ANIMAL_TYPES) do
        local a = RLTestUtils:createTestAnimal(typeName)
        assert("createTestAnimal " .. typeName .. " succeeds", a ~= nil, "non-nil", tostring(a))
    end

    -- =========================================================================
    -- Idempotent cleanup — calling twice leaves state clean
    -- =========================================================================

    RLTestUtils:cleanupTestAnimals()
    RLTestUtils:cleanupTestAnimals()
    -- Verify second cleanup didn't corrupt state — counter still 0, can still create
    local afterDouble = RLTestUtils:createTestAnimal("COW")
    assert("cleanupTestAnimals idempotent — can create after double cleanup",
        afterDouble ~= nil and afterDouble.uniqueId == RLTestUtils.TEST_PREFIX .. "1",
        RLTestUtils.TEST_PREFIX .. "1", afterDouble and afterDouble.uniqueId or "nil")

    -- Final cleanup
    RLTestUtils:cleanupTestAnimals()
end
