---------------------------------------------------------------------------
-- Voxelis - Vox Coloring
-- Adds dynamic dyes, registers dyeable blocks/items, and supports customization
---------------------------------------------------------------------------

-- Initialize the global table for this mod
vox_coloring = {}

-- Register dyes dynamically based on vox_colors
for color_name, color_hex in pairs(vox_colors) do
    if type(color_hex) == "string" and vox_colors.validate(color_hex) then
        minetest.register_craftitem("vox_coloring:dye_" .. color_name:lower(), {
            description = color_name .. " Dye",
            inventory_image = "dye_template.png^[multiply:" .. color_hex,
            groups = {dye = 1},
        })
    end
end

-- Table to hold registered dyeable items
local dyeable_registry = {}

-- Function for other mods to register colorable items or blocks
function vox_coloring.register_dyeable(modname, base_item)
    dyeable_registry[modname] = dyeable_registry[modname] or {}
    table.insert(dyeable_registry[modname], base_item)

    -- Get the original node definition
    local base_item_full = modname .. ":" .. base_item
    local base_def = minetest.registered_nodes[base_item_full]

    if not base_def then
        minetest.log("error", "[vox_coloring] Failed to register dyeable item: " .. base_item_full .. " does not exist.")
        return
    end

    -- Derive the template texture by appending `_colorize` to the base texture filename
    local base_texture = base_def.tiles and base_def.tiles[1]
    if not base_texture then
        minetest.log("error", "[vox_coloring] No texture found for " .. base_item_full)
        return
    end
    local colorize_texture = base_texture:gsub("%.png$", "_colorize.png")

    -- Iterate over all colors and register dyeable variants
    for color_name, color_hex in pairs(vox_colors) do
        if type(color_hex) == "string" then
            local colored_item = modname .. ":" .. base_item .. "_" .. color_name:lower()

            -- Register the colored version of the item/block
            minetest.register_node(colored_item, {
                description = base_def.description .. " (" .. color_name .. ")",
                tiles = {colorize_texture .. "^[multiply:" .. color_hex},
                groups = base_def.groups or {},
            })

            -- Register recipe to dye the item/block
            minetest.register_craft({
                output = colored_item,
                recipe = {
                    {base_item_full, "vox_coloring:dye_" .. color_name:lower()},
                },
            })

            -- Register recipe to undye the item/block
            minetest.register_craft({
                output = base_item_full,
                recipe = {
                    {colored_item, "vox_coloring:cleaning_solvent"},
                },
                replacements = {{"vox_coloring:cleaning_solvent", "bucket:bucket"}},
            })
        end
    end
end

-- Function to unregister a dyeable item or block
function vox_coloring.unregister_dyeable(modname, base_item)
    if not dyeable_registry[modname] then return end
    for i, item in ipairs(dyeable_registry[modname]) do
        if item == base_item then
            table.remove(dyeable_registry[modname], i)
            break
        end
    end

    -- Remove all colored variants and recipes
    for color_name, _ in pairs(vox_colors) do
        local colored_item = modname .. ":" .. base_item .. "_" .. color_name:lower()
        minetest.unregister_item(colored_item)
    end
end

-- Spraygun Tool
minetest.register_tool("vox_coloring:spraygun", {
    description = "Spraygun",
    inventory_image = "spraygun.png",
    on_use = function(itemstack, user, pointed_thing)
        if pointed_thing.type == "node" then
            local node = minetest.get_node(pointed_thing.under)
            local meta = itemstack:get_meta()
            local dye_color = meta:get_string("dye_color")

            if dye_color and vox_colors[dye_color:upper()] then
                local modname, item_base = node.name:match("^(.-):(.*)")
                if modname and item_base then
                    local colored_item = modname .. ":" .. item_base .. "_" .. dye_color:lower()
                    if minetest.registered_nodes[colored_item] then
                        minetest.swap_node(pointed_thing.under, {name = colored_item})
                        itemstack:add_wear(65535 / 100) -- Simulate durability loss
                        minetest.chat_send_player(user:get_player_name(), "Dyed with " .. dye_color .. "!")
                    else
                        minetest.chat_send_player(user:get_player_name(), "Cannot dye this object.")
                    end
                else
                    minetest.chat_send_player(user:get_player_name(), "No valid target for dye.")
                end
            else
                minetest.chat_send_player(user:get_player_name(), "No valid dye loaded in the spraygun.")
            end
        end
        return itemstack
    end,
})

-- Add dye to the spraygun
minetest.register_craftitem("vox_coloring:dye_cartridge", {
    description = "Dye Cartridge",
    inventory_image = "dye_cartridge.png",
    on_place = function(itemstack, user, pointed_thing)
        local wielded = user:get_wielded_item()
        if wielded:get_name() == "vox_coloring:spraygun" then
            local meta = wielded:get_meta()
            local dye_color = itemstack:get_name():match("vox_coloring:dye_(%w+)")
            if dye_color then
                meta:set_string("dye_color", dye_color)
                minetest.chat_send_player(user:get_player_name(), "Spraygun loaded with " .. dye_color .. " dye!")
                return itemstack:take_item()
            else
                minetest.chat_send_player(user:get_player_name(), "Failed to load dye into the spraygun.")
            end
        end
        return itemstack
    end,
})

-- Cleaning Solvent
minetest.register_craftitem("vox_coloring:cleaning_solvent", {
    description = "Cleaning Solvent",
    inventory_image = "cleaning_solvent.png",
    on_use = function(itemstack, user, pointed_thing)
        if pointed_thing.type == "node" then
            local node = minetest.get_node(pointed_thing.under)
            local modname, item_base = node.name:match("^(.-):(.*)")
            if modname and item_base then
                local base_item = item_base:match("^(.-)_")
                if base_item then
                    local original_item = modname .. ":" .. base_item
                    if minetest.registered_nodes[original_item] then
                        minetest.swap_node(pointed_thing.under, {name = original_item})
                        itemstack:take_item()
                        minetest.chat_send_player(user:get_player_name(), "Reverted to original state.")
                    else
                        minetest.chat_send_player(user:get_player_name(), "This block cannot be cleaned.")
                    end
                else
                    minetest.chat_send_player(user:get_player_name(), "No dye detected on this block.")
                end
            else
                minetest.chat_send_player(user:get_player_name(), "No dye detected on this block.")
            end
        end
        return itemstack
    end,
})

-- Recipe for Cleaning Solvent
minetest.register_craft({
    output = "vox_coloring:cleaning_solvent",
    recipe = {
        {"vox_core:soap", "bucket:water_bucket", "vox_core:salt"},
        {"vox_core:ash", "", ""},
    },
    replacements = {{"bucket:water_bucket", "bucket:bucket"}},
})

-- Cleaning Station
minetest.register_node("vox_coloring:cleaning_station", {
    description = "Cleaning Station",
    tiles = {"cleaning_station_top.png", "cleaning_station_side.png"},
    groups = {cracky = 2},
    on_rightclick = function(pos, node, player, itemstack, pointed_thing)
        local inv = player:get_inventory()
        if inv:contains_item("main", "vox_coloring:cleaning_solvent") then
            local node_name = minetest.get_node(pointed_thing.under).name
            local modname, item_base = node_name:match("^(.-):(.*)")
            if modname and item_base then
                local base_item = item_base:match("^(.-)_")
                if base_item then
                    local original_item = modname .. ":" .. base_item
                    if minetest.registered_nodes[original_item] then
                        minetest.swap_node(pointed_thing.under, {name = original_item})
                        inv:remove_item("main", "vox_coloring:cleaning_solvent")
                        minetest.chat_send_player(player:get_player_name(), "Reverted to original state.")
                    else
                        minetest.chat_send_player(player:get_player_name(), "This block cannot be cleaned.")
                    end
                else
                    minetest.chat_send_player(player:get_player_name(), "No dye detected on this block.")
                end
            else
                minetest.chat_send_player(player:get_player_name(), "No dye detected on this block.")
            end
        else
            minetest.chat_send_player(player:get_player_name(), "You need cleaning solvent to clean blocks.")
        end
    end,
})
