local mod_name = minetest.get_current_modname()
local mod_path = minetest.get_modpath(mod_name)
local S = minetest.get_translator(mod_name)

local MAX_WEAR = 65534

pmb_combat.cooldown = {}


local function clamp(a,min,max)
    return math.min(math.max(a, min),max)
end


-- un-wears a tool and returns wear in seconds
function pmb_combat.cooldown.wear_tick(itemstack, max_sec, dtime)
    -- instant if 0, also avoids x/0
    if max_sec == 0 then
        itemstack:set_wear(0)
        return itemstack
    end

    local wear = itemstack:get_wear()
    local new_wear = clamp(wear - (MAX_WEAR / max_sec) * dtime, 0, MAX_WEAR)
    itemstack:set_wear(new_wear)
    return itemstack
end


-- returns true if it can be used and is in end of windup state
function pmb_combat.cooldown.is_ready(itemstack)
    local def = itemstack:get_definition()
    local windup = itemstack:get_meta():get_string("_mode") ~= "complete"
    if (windup or (def and def.windup == 0)) and itemstack:get_wear() == 0 then return true
    else return false end
end


-- sets back to max wear so it can count back up again
function pmb_combat.cooldown.wear_start(itemstack, mode)
    local meta = itemstack:get_meta()
    if meta:get_string("_mode") ~= mode then
        itemstack:set_wear(MAX_WEAR)
        meta:set_string("_mode", mode)
    end
    return itemstack
end


-- just tests if can use, based on wear
function pmb_combat.cooldown.can_use(itemstack)
    return itemstack:get_wear() == 0
end


-- returns "windup" or "cooldown" or ""
function pmb_combat.cooldown.get_mode(itemstack)
    return itemstack:get_meta():get_string("_mode") or ""
end


-- call this when you switch from this to something else
function pmb_combat.cooldown.on_wield_change_from(itemstack, player)
    if pmb_combat.cooldown.can_use(itemstack) then
        return itemstack
    end

    local mode = itemstack:get_meta():get_string("_mode")
    if mode == "windup" then
        return pmb_combat.cooldown.windup_cancel(itemstack, player)
    end
end


function pmb_combat.cooldown.on_trigger(itemstack, player, trigger_name)
    local def = itemstack:get_definition()
    if def[trigger_name] then
        return def[trigger_name](itemstack, player) or itemstack
    end
    return itemstack
end


function pmb_combat.cooldown.windup_start(itemstack, player)
    itemstack = ItemStack(itemstack)
    pmb_combat.cooldown.wear_start(itemstack, "windup")
    return pmb_combat.cooldown.on_trigger(itemstack, player, "_on_windup_start") or itemstack
end


function pmb_combat.cooldown.windup_cancel(itemstack, player)
    if pmb_combat.cooldown.get_mode(itemstack) ~= "windup" then return itemstack end
    itemstack = ItemStack(itemstack)
    itemstack:get_meta():set_string("_mode", "cooldown")
    itemstack = pmb_combat.cooldown.on_trigger(itemstack, player, "_on_windup_cancelled") or itemstack

    -- only call the complete func if _on_windup_cancelled is not defined
    if itemstack:get_definition()._on_windup_cancelled then return itemstack end
    -- allows to make cooldown happen when cancelling
    return pmb_combat.cooldown.cooldown_complete(itemstack, player)
end


function pmb_combat.cooldown.windup_complete(itemstack, player)
    itemstack = ItemStack(itemstack)
    itemstack:get_meta():set_string("_mode", "complete")
    return pmb_combat.cooldown.on_trigger(itemstack, player, "_on_windup_complete") or itemstack
end


function pmb_combat.cooldown.cooldown_start(itemstack, player)
    itemstack = ItemStack(itemstack)
    itemstack:get_meta():set_string("_mode", "")
    pmb_combat.cooldown.wear_start(itemstack, "cooldown")
    return pmb_combat.cooldown.on_trigger(itemstack, player, "_on_cooldown_start") or itemstack
end


function pmb_combat.cooldown.cooldown_complete(itemstack, player)
    itemstack = ItemStack(itemstack)
    itemstack:get_meta():set_string("_mode", "")
    itemstack:set_wear(0)
    return pmb_combat.cooldown.on_trigger(itemstack, player, "_on_cooldown_complete") or itemstack
end


function pmb_combat.cooldown.attempt_to_use(itemstack, player, pointed_thing)
    if pmb_combat.cooldown.can_use(itemstack) then
        pmb_combat.cooldown.windup_start(itemstack, player)
    end
end


-- update all items, by going through entire inventory
function pmb_combat.cooldown.update_all_in_inventory(player, dtime)
    local inv = player:get_inventory()
    for i = 0, inv:get_size("main") do
        local itemstack = inv:get_stack("main", i)
        local def = itemstack:get_definition()
        if def and (def._cooldown or def._windup) then
            local mode = itemstack:get_meta():get_string("_mode") or "" --"windup" or "cooldown"

            --> change durability based on time
            if mode == "cooldown" or mode == "windup" then
                itemstack = mode and pmb_combat.cooldown.wear_tick(itemstack, def["_"..mode] or 0, dtime)
            end

            -- wear is 0 / full durability so trigger windup or cooldown end triggers
            if itemstack:get_wear() == 0 then
                if mode == "windup" then
                    itemstack = pmb_combat.cooldown.windup_complete(itemstack, player)
                elseif mode == "cooldown" then
                    itemstack = pmb_combat.cooldown.cooldown_complete(itemstack, player)
                end
            end

            if not itemstack:equals(inv:get_stack("main", i)) then
                inv:set_stack("main", i, itemstack)
            end
        end
    end
end


minetest.register_globalstep(function(dtime)
    for i, player in ipairs(minetest.get_connected_players()) do
        pmb_combat.cooldown.update_all_in_inventory(player, dtime)
    end
end)





minetest.register_tool("pmb_combat:cooldown_debug", {
    description = S("For debug"),
    inventory_image = "pmb_wooden_pickaxe.png^[transformR180",
    groups = { not_in_creative_inventory = 1 },
    on_use = function(itemstack, player, pointed_thing)
        if pmb_combat.cooldown.can_use(itemstack) then
            return pmb_combat.cooldown.windup_start(itemstack, player)
        end
    end,
    on_deselect = function(itemstack, player)
        return pmb_combat.cooldown.on_wield_change_from(itemstack, player)
    end,
    on_step = function(itemstack, player, dtime)
    end,
    _cooldown = 4,
    _windup = 1,
    _on_windup_start = function(itemstack, player)
        minetest.log("windup start")
        return itemstack
    end,
    _on_windup_cancelled = function(itemstack, player)
        minetest.log("windup cancel")
        return pmb_combat.cooldown.cooldown_start(itemstack, player)
    end,
    _on_windup_complete = function(itemstack, player)
        minetest.log("hit")
        return pmb_combat.cooldown.cooldown_start(itemstack, player)
    end,
    _on_cooldown_start = function(itemstack, player)
        minetest.log("cooldown")
        return itemstack
    end,
    _on_cooldown_complete = function(itemstack, player)
        minetest.log("ready")
        return itemstack
    end,
})



