-- RLReproductionTests.lua
-- Purpose: Tests for reproduction eligibility, delta calculation, and meter
-- Author: Ritter
-- Validates: getReproductionDelta(), changeReproduction(), getCanReproduce()
-- Pattern: Test public interface, boundary conditions
-- ASSUMES: vanilla FS25 subType values (no map mod overrides)

RLReproductionTests = {}

local Log = RmLogging.getLogger("RLRM")

--- Run all reproduction tests.
--- Tests delta calculation, reproduction meter, and eligibility checks.
--- @param assert function Assert closure from RLTestRunner
function RLReproductionTests:runAll(assert)
    Log:info("--- Reproduction Tests ---")

    self:testReproductionDelta(assert)
    self:testReproductionMeter(assert)
    self:testReproductionEligibility(assert)

    -- Cleanup
    RLTestUtils:cleanupTestAnimals()
end

-- =========================================================================
-- Reproduction Delta Calculation
-- =========================================================================

--- Test getReproductionDelta() returns correct value.
--- Formula: floor((100 / duration) / daysPerPeriod)
--- @param assert function Assert closure from RLTestRunner
function RLReproductionTests:testReproductionDelta(assert)
    Log:info("--- Reproduction Delta ---")

    local cow = RLTestUtils:createTestAnimal("COW")
    local subType = cow:getSubType()
    local duration = subType.reproductionDurationMonth
    local daysPerPeriod = g_currentMission.environment.daysPerPeriod

    local expected = math.floor((100 / duration) / daysPerPeriod)
    local actual = cow:getReproductionDelta()
    Log:debug("  reproductionDelta: duration=%d daysPerPeriod=%d expected=%d actual=%d",
        duration, daysPerPeriod, expected, actual)
    assert("getReproductionDelta matches formula",
        actual == expected, expected, actual)

    -- Delta is positive (duration > 0 for COW)
    assert("getReproductionDelta is positive", actual > 0, ">0", actual)

    RLTestUtils:cleanupTestAnimals()
end

-- =========================================================================
-- Reproduction Meter
-- =========================================================================

--- Test changeReproduction() adds delta and clamps to 0-100.
--- NOTE: changeReproduction uses math.max(delta, 1) so minimum delta is 1.
--- @param assert function Assert closure from RLTestRunner
function RLReproductionTests:testReproductionMeter(assert)
    Log:info("--- Reproduction Meter ---")

    -- changeReproduction(50) from 0 → reproduction=50
    local cow1 = RLTestUtils:createTestAnimal("COW", { reproduction = 0 })
    cow1:changeReproduction(50)
    assert("changeReproduction(50) from 0 gives 50",
        cow1.reproduction == 50, 50, cow1.reproduction)

    -- changeReproduction(200) from 0 → clamps to 100
    local cow2 = RLTestUtils:createTestAnimal("COW", { reproduction = 0 })
    cow2:changeReproduction(200)
    assert("changeReproduction(200) clamps to 100",
        cow2.reproduction == 100, 100, cow2.reproduction)

    RLTestUtils:cleanupTestAnimals()
end

-- =========================================================================
-- Reproduction Eligibility
-- =========================================================================

--- Test getCanReproduce() eligibility checks.
--- Requires female + male in same clusterSystem for positive case.
--- @param assert function Assert closure from RLTestRunner
function RLReproductionTests:testReproductionEligibility(assert)
    Log:info("--- Reproduction Eligibility ---")

    -- Create shared clusterSystem with both female and male for positive tests
    RLTestUtils:cleanupTestAnimals()
    local cs = RLTestUtils:getSharedMockClusterSystem()

    -- Get subType to know reproductionMinAgeMonth
    local tempCow = RLTestUtils:createTestAnimal("COW")
    local subType = tempCow:getSubType()
    local minReproAge = subType.reproductionMinAgeMonth
    local minReproHealth = subType.reproductionMinHealth
    Log:debug("  COW reproductionMinAgeMonth=%s reproductionMinHealth=%s",
        tostring(minReproAge), tostring(minReproHealth))
    RLTestUtils:cleanupTestAnimals()

    -- Positive case: female cow, adult, healthy, male in pen
    -- Both must be in the SAME shared clusterSystem
    local female = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "female",
        monthsSinceLastBirth = 3,  -- past recovery period (> 2)
    })
    local male = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "male",
    })
    local canReproduce = female:getCanReproduce()
    Log:debug("  getCanReproduce positive case: %s", tostring(canReproduce))
    assert("female cow adult + male in pen can reproduce",
        canReproduce == true, true, canReproduce)

    RLTestUtils:cleanupTestAnimals()

    -- Underage: cow below reproductionMinAgeMonth → false
    local underageFemale = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge - 1,
        health = 100,
        gender = "female",
        monthsSinceLastBirth = 3,
    })
    -- Need a male in the same clusterSystem
    local maleForUnderage = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "male",
    })
    local canReproUnderage = underageFemale:getCanReproduce()
    assert("underage cow cannot reproduce",
        canReproUnderage == false, false, canReproUnderage)

    RLTestUtils:cleanupTestAnimals()

    -- Recovery period: monthsSinceLastBirth=0, isParent=true → false
    -- NOTE: isParent=true is REQUIRED here. The guard is:
    --   (monthsSinceLastBirth > 2 OR NOT isParent)
    -- Without isParent=true, the second branch (NOT false = true) would bypass the check.
    local recentMother = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "female",
        monthsSinceLastBirth = 0,
        isParent = true,
    })
    local maleForRecovery = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "male",
    })
    local canReproRecovery = recentMother:getCanReproduce()
    assert("recent mother (monthsSinceLastBirth=0) cannot reproduce",
        canReproRecovery == false, false, canReproRecovery)

    RLTestUtils:cleanupTestAnimals()

    -- Low health: health below reproductionMinHealth → false
    -- reproductionMinHealth is a factor (0-1), getHealthFactor() = health/100
    local minHealthValue = math.floor(minReproHealth * 100)
    local unhealthy = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = math.max(minHealthValue - 1, 0),
        gender = "female",
        monthsSinceLastBirth = 3,
    })
    local maleForUnhealthy = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "male",
    })
    local canReproUnhealthy = unhealthy:getCanReproduce()
    assert("unhealthy cow below reproductionMinHealth cannot reproduce",
        canReproUnhealthy == false, false, canReproUnhealthy)

    RLTestUtils:cleanupTestAnimals()

    -- RLRM-64: Male gender guard — males must never return true from getCanReproduce()
    -- A lone male in pen currently finds itself as an eligible mate via hasMaleAnimalInPen()
    local loneMale = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "male",
    })
    local canReproLoneMale = loneMale:getCanReproduce()
    assert("RLRM-64: lone male cannot reproduce",
        canReproLoneMale == false, false, canReproLoneMale)

    RLTestUtils:cleanupTestAnimals()

    -- RLRM-64: Male with female present — male still cannot reproduce
    local maleWithFemale = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "male",
    })
    local femaleCompanion = RLTestUtils:createTestAnimal("COW", {
        age = minReproAge + 1,
        health = 100,
        gender = "female",
        monthsSinceLastBirth = 3,
    })
    local canReproMaleWithFemale = maleWithFemale:getCanReproduce()
    assert("RLRM-64: male with female present cannot reproduce",
        canReproMaleWithFemale == false, false, canReproMaleWithFemale)
    -- Sanity: the female in the same pen CAN reproduce
    local canReproFemaleCompanion = femaleCompanion:getCanReproduce()
    assert("RLRM-64: female companion can still reproduce",
        canReproFemaleCompanion == true, true, canReproFemaleCompanion)

    RLTestUtils:cleanupTestAnimals()
end
