--[[
    Full rewrite of Rotten Meat addon by HarukaSai for EFP (visit at: https://discord.com/invite/stalker-efp)

    Created: 13-11-2022

    Credits for original addon: Arszi

    Features:
        - Rewritten logic
        - Refrigiration
        - MCM configuration
]]

local mcm_id = "meat_spoiling"

local expiration_time = nil
local expiration_table = {}

local ini_meat = ini_file_ex("plugins\\meat_spoiling_settings.ltx")
meats = utils_data.collect_section(ini_meat.ini, "meats", true)

local function t2c(t)
	if not t then return nil end
	local ct = game.CTime()
	ct:set(t.Y,t.M,t.D,t.h,t.m,t.s,t.ms)
	return ct
end

local function c2t(ct)
	if not ct then return nil end
	local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0
	Y, M, D, h, m, s, ms = ct:get(Y, M, D, h, m, s, ms)
	return { Y=Y, M=M, D=D, h=h, m=m, s=s, ms=ms }
end

local previous_time = nil

function actor_on_update()
    local curr_time = game.get_game_time()

    if (previous_time == nil) then previous_time = curr_time end
  
    if not (curr_time:diffSec(previous_time) > 1) then
        return
    end

    previous_time = curr_time

    tick_expiration()
end

function actor_on_item_take(item)
    local id = item:id()
    local sec = item:section()

    if not (meats[sec] and (not expiration_table[id])) then
        return
    end

    expiration_table[id] = {
        duration = string.match(sec, "meat_") and expiration_time.cooked or expiration_time.raw,
        last_update = c2t(game.get_game_time())
    }
end

function actor_on_item_use(obj)
    if (obj and expiration_table[obj:id()]) then
        expiration_table[obj:id()] = nil
    end
end

function get_meat_is_frozen(se_obj)
    if (not se_obj) then return false end

    local se_parent = se_obj.parent_id and se_obj.parent_id < 65535 and alife_object(se_obj.parent_id)
    
    if (not se_parent) or (se_parent:section_name() ~= "placeable_fridge") then
        return false
    end

    return true
end

function tick_expiration()
    local curr_time = game.get_game_time()

    for id, data in pairs(expiration_table) do
        repeat
            local se_obj = alife_object(id)
            
            if (not se_obj) or (not meats[se_obj:section_name()]) then
                expiration_table[id] = nil
                do break end
            end

            if (not get_meat_is_frozen(se_obj)) then
                data.duration = data.duration - curr_time:diffSec(t2c(data.last_update))
            end

            data.last_update = c2t(curr_time)
            
            if (data.duration <= 0) then
                expire_food(se_obj)
                expiration_table[id] = nil
            end
        until true
    end
end

function expire_food(se_obj)
    if (not se_obj.parent_id) or se_obj.parent_id >= 65535 then
        alife_release(se_obj)
        return
    end

    local se_parent = alife_object(se_obj.parent_id)
    
    alife_release(se_obj)

    if se_parent and (IsInvbox(se_parent) or se_parent.id == AC_ID) then
        alife_create_item("rotten_meat", se_parent)
    end
end

function save_state(m_data)
	m_data.expiration_table = expiration_table
end

function load_state(m_data)
	expiration_table = m_data.expiration_table or {}
end

function on_option_change()
    expiration_time = {
        raw = ui_mcm and ui_mcm.get(mcm_id .. "/expiration_hours_raw") * 60 * 60 or 48 * 60 * 60,
        cooked = ui_mcm and ui_mcm.get(mcm_id .. "/expiration_hours_cooked")  * 60 * 60 or 120 * 60 * 60
    }
end

local clr_frozen = GetARGB(40,0,197,255)

function get_meat_is_frozen_cell(cell)
    local se_obj = cell.ID and expiration_table[cell.ID] and alife_object(cell.ID)

    if get_meat_is_frozen(se_obj) then
        return true
    end
end

function on_game_start()
    RegisterScriptCallback("actor_on_item_use", actor_on_item_use)
    RegisterScriptCallback("save_state",save_state)
	RegisterScriptCallback("load_state",load_state)
    RegisterScriptCallback("actor_on_item_take",actor_on_item_take)
    RegisterScriptCallback("actor_on_update", actor_on_update)
    RegisterScriptCallback("on_option_change", on_option_change)

    rax_persistent_highlight.register("frozen_meat", function(cell)
        return get_meat_is_frozen_cell(cell) and clr_frozen or false
    end)
    
    local anchor_x = function(axis, margin, w)
        return (axis.w - w) - margin
    end

    local anchor_y = function(axis, margin, h)
        return margin
    end

    rax_icon_layers.register("frozen_meat", function(cell, obj, sec)
        if get_meat_is_frozen_cell(cell) then
            local axis = utils_xml.get_item_axis(sec)

            return {
                texture = "ui_icon_freeze", 
                x = anchor_x(axis, 2, 13), 
                y = anchor_y(axis, 2, 13), 
                w = 13, 
                h = 13
            }
        end
    end)
    
    on_option_change()
end