require "TimedActions/ISBaseTimedAction"
require "Map/SGlobalObjectSystem"
require "ISUI/ISInventoryPaneContextMenu"

BabiesRecipe = {}
BabiesRecipe.GetItemTypes = {}
BabiesRecipe.OnCanPerform = {}
BabiesRecipe.OnCreate = {}
BabiesRecipe.OnGiveXP = {}
BabiesRecipe.OnTest = {}


local Babies = {
    "Babies.Baby_01", "Babies.Baby_01_b", "Babies.Baby_02", "Babies.Baby_02_b",
    "Babies.Baby_03", "Babies.Baby_03_b", "Babies.Baby_07", "Babies.Baby_07_b",
    "Babies.Baby_08", "Babies.Baby_08_b", "Babies.Baby_09", "Babies.Baby_09_b",
    "Babies.Baby_10", "Babies.Baby_10_b", "Babies.Baby_11", "Babies.Baby_11_b",
    "Babies.Baby_12", "Babies.Baby_12_b", "Babies.Baby_13", "Babies.Baby_14",
}

local Carriers = {
    "Babies.Baby_carrier_blue_baby_01", "Babies.Baby_carrier_blue_baby_02",
    "Babies.Baby_carrier_blue_baby_03", "Babies.Baby_carrier_blue_baby_04",
    "Babies.Baby_carrier_blue_baby_01_bkp", "Babies.Baby_carrier_blue_baby_02_bkp",
    "Babies.Baby_carrier_blue_baby_03_bkp", "Babies.Baby_carrier_blue_baby_04_bkp",
}

-- Combine Babies and Carriers into AllBabyItems
local AllBabyItems = {}
for _, v in ipairs(Babies) do table.insert(AllBabyItems, v) end
for _, v in ipairs(Carriers) do table.insert(AllBabyItems, v) end

-- Function to retain the name after a recipe
-- Carrier

-- Helper function to transfer mod data
local function transferModData(source, target, keys)
    for _, key in ipairs(keys) do
        target:getModData()[key] = source:getModData()[key]
    end
end

-- Helper function to set baby name and feed time
local function setBabyNameAndFeedTime(result, baby, nameFormat)
    result:getModData().name = baby:getName()
    result:getModData().feedTime = baby:getModData().feedTime
    result:setName(string.format(getText(nameFormat), baby:getName()))
end

-- Function to retain the name after a recipe
function BabiesRecipe.OnCreate.GetCarrier(items, result, player)
    player:getInventory():AddItem("Babies.Baby_carrier_blue_floor")
    local carrier = items:get(0)
    transferModData(carrier, result, {"name", "feedTime"})
end

function BabiesRecipe.OnCreate.PutBabyInCarrier(items, result, _)
    local baby = items:get(0):getType() == "Baby_carrier_blue_floor" and items:get(1) or items:get(0)
    setBabyNameAndFeedTime(result, baby, "IGUI_Babies.Baby_Carrier")
end

function BabiesRecipe.OnCreate.GetBackPack(items, result, player)
    player:getInventory():AddItem("Babies.Baby_carrier_floor_bkp")
    local carrier = items:get(0)
    transferModData(carrier, result, {"name", "feedTime"})
end

function BabiesRecipe.OnCreate.PutBabyInBackpack(items, result, _)
    local baby = items:get(0):getType() == "Baby_carrier_floor_bkp" and items:get(1) or items:get(0)
    setBabyNameAndFeedTime(result, baby, "IGUI_Babies.Baby_Backpack")
end


function BabiesRecipe.OnCreate.KeepName(items, result, _)
    local item = items:get(0)
    result:setName(item:getDisplayName())
    result:getModData().feedTime = item:getModData().feedTime or getGametimeTimestamp()
end

function BabiesRecipe.OnCreate.OpenBabyFoodJar(items, result, player)
local inv = player:getInventory();
    result:setAge(0);
    inv:AddItem("Base.JarLid");
end

-- Function to feed the Baby 
function BabiesRecipe.OnCreate.FeedBaby(items, result, player)
    local item = items:get(1)
    local isTheFirstFeeding = false
    local gameTime = GameTime.getInstance();
    local sound = "Cry"
    local soundEmitter = player:getEmitter()

    local hour = gameTime:getHour()

    if item:getModData().feedTime == nil then -- if is the first time feeding the baby
        isTheFirstFeeding = true
        item:getModData().feedTime = getGametimeTimestamp()
        if item:isRinging() then --stops the alarm
            item:stopRinging()
        end
    end

    -- checks if the baby has already been fed in the last 4 hours
    if getGametimeTimestamp() - item:getModData().feedTime < 14400 then -- 14400 = 4 hours      
        if isTheFirstFeeding == false then
        player:Say("The baby vomits on you"); -- remember the translations !!!
        end
    end

    if getGametimeTimestamp() - item:getModData().feedTime >= 14400 or isTheFirstFeeding == true then
        -- Resets the timer if at least 4 hours passed from the last feeding 
        item:setHour((hour + 6) % 24)
        item:getModData().feedTime = getGametimeTimestamp()

        if item:isAlarmSet() == false then
        item:setAlarmSet(true) --sets the alarm on if is not, just in case
        end

        if  soundEmitter:isPlaying(sound) then
            soundEmitter:stopSoundByName(sound)
        end
        if item:isRinging() then --stops the alarm
            item:stopRinging()
        end
    end
end

-- did you just mute your child?
local function doNotTheChild()
    local player = getPlayer()
    local gameTime = GameTime.getInstance()
    local currentTime = getGametimeTimestamp()

    if not player then
        return
    end

    local inventory = player:getInventory()
    local items = inventory:getItems()

    if items then
        for i = 0, items:size() - 1 do
            local item = items:get(i)
            for _, o in ipairs(Babies) do
                if o == item:getFullType() then
                    local lastFedTime = item:getModData().feedTime or 0
                    local timeSinceLastFed = currentTime - lastFedTime
                    local hoursSinceLastFed = timeSinceLastFed / 3600 -- Convert milliseconds to hours

                    if hoursSinceLastFed > 6 and not item:isRinging() then
                        local currentMin = gameTime:getMinutes()
                        local currentHour = gameTime:getHour()

                        local newItemHour = currentHour
                        local newItemMin = currentMin + 10

                        -- Adjust newItemMin and newItemHour if newItemMin exceeds 60
                        if newItemMin >= 60 then
                            newItemHour = (newItemHour + 1) % 24
                            newItemMin = newItemMin % 60
                        end

                        -- Adjust newItemHour and newItemMin if newItemHour exceeds 24
                        if newItemHour >= 24 then
                            newItemHour = newItemHour % 24
                        end

                        -- Ensure newItemMin is at least 10 minutes ahead of currentMin
                        if newItemMin <= currentMin then
                            newItemMin = currentMin + 10
                            if newItemMin >= 60 then
                                newItemHour = (newItemHour + 1) % 24
                                newItemMin = newItemMin % 60
                            end
                        end

                        item:setHour(newItemHour)
                        item:setMinute(newItemMin)
                        item:setAlarmSet(true)
                    end
                end
            end
        end
    end
end


-- Checks if the player turned off the alarm every minute and reactivates it
local function IsTheBabyAlarmOn()
    local player = getPlayer()
    local gameTime = GameTime.getInstance()
    local min = gameTime:getMinutes()
    local hour = gameTime:getHour()

    if not player then
        return
    end

    local inventory = player:getInventory()
    local items = inventory:getItems()
    local currentTime = getGametimeTimestamp()


    if items then
        for i = 0, items:size() - 1 do
            local item = items:get(i)

            for _, o in ipairs(Babies) do
                if o == item:getFullType() then
                    local lastFedTime = item:getModData().feedTime or 0
                    local timeSinceLastFed = currentTime - lastFedTime
                    local hoursSinceLastFed = timeSinceLastFed /3600 -- Convert milliseconds to hours

                if not item:isAlarmSet() and hoursSinceLastFed > 6  then
                    local newItemHour = (hour + math.floor((min + 10) / 60)) % 24
                    local newItemMin = (min + 10) % 60
                    if newItemHour ~= item:getHour() or newItemMin ~= item:getMinute() then
                        item:setHour(newItemHour)
                        item:setMinute(newItemMin)
                        item:setAlarmSet(true)
                    end
                end
            end
        end


        end
    end
end

local function IsTheBabyEquipped()
    local player = getPlayer()
    --local gameTime = GameTime.getInstance()

    if not player then
        return
    end

    local inventory = player:getInventory()
    local items = inventory:getItems()
    local currentTime = getGametimeTimestamp()
    local sound = "Cry"
    local soundEmitter = player:getEmitter()

    if items then
        local babyfound = 0
        for i = 0, items:size() - 1 do
            local item = items:get(i)
            -- Itera sulla tabella combinata
            for _, o in ipairs(AllBabyItems) do
                if o == item:getFullType() then
                    --print("Baby item found")
                    babyfound = babyfound + 1
                    --print("Baby " .. babyfound)

                    -- Esegui il controllo solo se l'oggetto corrisponde
                    if babyfound > 0 then
                        local lastFedTime = item:getModData().feedTime or 0
                        local timeSinceLastFed = currentTime - lastFedTime
                        local hoursSinceLastFed = timeSinceLastFed / 3600 -- Convert milliseconds to hours                   

                        if hoursSinceLastFed > 6 and not soundEmitter:isPlaying(sound) then
                            soundEmitter:playSound(sound)
                            --print("Baby is crying")
                        end

                        if soundEmitter:isPlaying(sound) then
                            --player:Say("Sound found")
                            -- Controlla se l'attributo isRinging esiste prima di utilizzarlo
                            if item.isRinging and item:isRinging() then
                                item:stopRinging()
                            end
                        end
                    end
                end
            end
        end

        if babyfound == 0 and soundEmitter:isPlaying(sound) then
            soundEmitter:stopSoundByName(sound)
            --print("No baby found")
            --player:Say("No sound")
        end
    end
end



local function IsTheBabyBeingFed()
    local player = getPlayer()

    if not player then
        return
    end

    local inventory = player:getInventory()
    local items = inventory:getItems()
    local sound = "Cry"
    local sound2 = "Feed"
    local soundEmitter = player:getEmitter()

    if items then
        local babyfound = 0
        for i = 0, items:size() - 1 do
            local item = items:get(i)
            -- Itera sulla tabella combinata
            for _, o in ipairs(AllBabyItems) do
                if o == item:getFullType() then
                    --print("Baby item found")
                    babyfound = babyfound + 1
                    --print("Baby " .. babyfound)

                    -- Esegui il controllo solo se l'oggetto corrisponde
                    if babyfound > 0 then

                        if soundEmitter:isPlaying(sound2) then
                        soundEmitter:stopSoundByName(sound)
                        end

                    end         
                end                  
            end
        end

        if babyfound == 0 and soundEmitter:isPlaying(sound) then
            soundEmitter:stopSoundByName(sound)
            --print("No baby found")
            --player:Say("No sound")
        end
    end 
end


-- Removes the SetAlarm option if the item is a Baby
local function OnFillInventoryObjectContextMenu(player, context, items)
    items = ISInventoryPane.getActualItems(items)
    local babyWatch = nil
    for _, item in ipairs(items) do

        for _, o in ipairs(Babies) do
            if o == item:getFullType() then
                babyWatch = item
                break
            end
        end
end

if babyWatch ~= nil then
    context:removeOptionByName(getText("ContextMenu_SetAlarm"))
    context:removeOptionByName(getText("ContextMenu_StopAlarm"))


end
end

Events.EveryOneMinute.Add(IsTheBabyBeingFed)
Events.OnFillInventoryObjectContextMenu.Add(OnFillInventoryObjectContextMenu)
Events.EveryTenMinutes.Add(IsTheBabyAlarmOn)
Events.EveryTenMinutes.Add(doNotTheChild)
Events.EveryOneMinute.Add(IsTheBabyEquipped)
