local states = {
    {
        id = "dry", desc = "Dry Sponge", tex = "mysponge_sponge.png", size = 0.5, 
        inv = true, next_state = nil, dry_time = 0, drip_count = 0, steam_count = 0, water_yield = 0
    },
    {
        id = "moist", desc = "Moist Sponge", tex = "mysponge_sponge2.png", size = 0.7, 
        inv = false, next_state = "dry", dry_time = 45, drip_count = 2, steam_count = 1, water_yield = 1
    },
    {
        id = "wet", desc = "Wet Sponge", tex = "mysponge_sponge3.png", size = 0.85, 
        inv = false, next_state = "moist", dry_time = 60, drip_count = 8, steam_count = 3, water_yield = 2
    },
    {
        id = "soaked", desc = "Soaked Sponge", tex = "mysponge_sponge4.png", size = 1.0, 
        inv = false, next_state = "wet", dry_time = 90, drip_count = 25, steam_count = 10, water_yield = 3
    },
}

local function is_touching_water(pos)
    local sides = {
        {x = pos.x + 1, y = pos.y,     z = pos.z},
        {x = pos.x - 1, y = pos.y,     z = pos.z},
        {x = pos.x,     y = pos.y + 1, z = pos.z},
        {x = pos.x,     y = pos.y - 1, z = pos.z},
        {x = pos.x,     y = pos.y,     z = pos.z + 1},
        {x = pos.x,     y = pos.y,     z = pos.z - 1},
    }
    for _, s_pos in ipairs(sides) do
        local node = core.get_node(s_pos)
        if core.get_item_group(node.name, "water") ~= 0 then
            return true
        end
    end
    return false
end

local function absorb_water(pos)
    if not is_touching_water(pos) then
        return false
    end

    local radius = 3
    local nodes = core.find_nodes_in_area(
        {x = pos.x - radius, y = pos.y - radius, z = pos.z - radius},
        {x = pos.x + radius, y = pos.y + radius, z = pos.z + radius},
        {"group:water"}
    )
    
    if #nodes > 0 then
        for _, p in ipairs(nodes) do
            core.remove_node(p)
        end
        core.set_node(pos, {name = "mysponge:sponge_soaked"})
        return true
    end
    return false
end

local state_data = {}
for _, s in ipairs(states) do state_data["mysponge:sponge_" .. s.id] = s end

for _, state in ipairs(states) do
    local box_size = state.size / 2
    local groups = {dig_immediate = 3, sponge = 1}
    if state.id == "dry" then groups.sponge_dry = 1 end
    if not state.inv then groups.not_in_creative_inventory = 1 end

    core.register_node("mysponge:sponge_" .. state.id, {
        description = state.desc,
        tiles = {state.tex},
        drawtype = "nodebox",
        paramtype = "light",
        groups = groups,
        node_box = {
            type = "fixed",
            fixed = {-box_size, -0.5, -box_size, box_size, -0.5 + state.size, box_size},
        },
        
        on_construct = function(pos)
            if state.id == "dry" then
                absorb_water(pos)
            elseif state.next_state then
                core.get_node_timer(pos):start(2)
            end
        end,

        on_neighbor_update = function(pos, node, neighbor_pos)
            if state.id == "dry" then
                absorb_water(pos)
            end
        end,

        on_punch = function(pos, node, puncher, pointed_thing)
            if not puncher or not state.next_state then return end
            
            local held_item = puncher:get_wielded_item()
            if held_item:get_name() == "bucket:bucket_empty" then
                core.set_node(pos, {name = "mysponge:sponge_" .. state.next_state})
                
                held_item:take_item()
                puncher:set_wielded_item(held_item)
                
                local inv = puncher:get_inventory()
                local water_bucket = ItemStack("bucket:bucket_water")
                if inv:room_for_item("main", water_bucket) then
                    inv:add_item("main", water_bucket)
                else
                    core.add_item(puncher:get_pos(), water_bucket)
                end
                
                core.sound_play("default_water_footstep", {pos = pos, gain = 0.5})
            end
        end,

        on_timer = function(pos, elapsed)
            local surrounding = core.find_nodes_in_area(vector.subtract(pos, 1), vector.add(pos, 1), {"group:lava"})
            if #surrounding > 0 then
                core.set_node(pos, {name = "mysponge:dried_leaves"})
                return false
            end

            if not state.next_state then return false end

            local meta = core.get_meta(pos)
            local neighbors = core.find_nodes_in_area(vector.subtract(pos, 1), vector.add(pos, 1), {"air"})
            
            if #neighbors > 0 then
                meta:set_int("is_drying", 1)
                local current_dry = (meta:get_float("dry_progress") or 0) + elapsed
                if current_dry >= state.dry_time then
                    core.set_node(pos, {name = "mysponge:sponge_" .. state.next_state})
                    return false
                end
                meta:set_float("dry_progress", current_dry)
            else
                meta:set_int("is_drying", 0)
            end
            return true
        end,

        on_blast = function(pos, intensity)
            core.remove_node(pos)
            return {"mysponge:sponge_" .. state.id}
        end,
    })

    if state.water_yield > 0 then
        core.register_craft({
            type = "cooking",
            output = "mysponge:sponge_dry",
            recipe = "mysponge:sponge_" .. state.id,
            cooktime = 3,
            replacements = {
                {"mysponge:sponge_" .. state.id, "default:water_source " .. state.water_yield}
            }
        })
    end
end
core.register_abm({
    label = "Sponge Leaf Drying",
    nodenames = {"group:sponge"},
    interval = 2.0,
    chance = 5,
    action = function(pos, node)
        local radius = 1
        local leaf_nodes = core.find_nodes_in_area(
            {x = pos.x - radius, y = pos.y - radius, z = pos.z - radius},
            {x = pos.x + radius, y = pos.y + radius, z = pos.z + radius},
            {"group:leaves"}
        )
        
        for _, leaf_pos in ipairs(leaf_nodes) do
            core.set_node(leaf_pos, {name = "mysponge:dried_leaves"})
        end
    end,
})

core.register_abm({
    label = "Sponge Absorption Check",
    nodenames = {"group:sponge_dry"},
    neighbors = {"group:water"},
    interval = 1.0,
    chance = 1,
    action = function(pos, node)
        absorb_water(pos)
    end,
})

core.register_abm({
    label = "Sponge Effects",
    nodenames = {"group:sponge"},
    interval = 1.0,
    chance = 1,
    action = function(pos, node)
        local data = state_data[node.name]
        if not data then return end
        if data.drip_count > 0 then
            core.add_particlespawner({
                amount = data.drip_count,
                time = 1,
                minpos = {x=pos.x-0.2, y=pos.y-0.4, z=pos.z-0.2},
                maxpos = {x=pos.x+0.2, y=pos.y-0.1, z=pos.z+0.2},
                minvel = {x=0, y=-1, z=0},
                maxvel = {x=0, y=-2, z=0},
                minacc = {x=0, y=-9.8, z=0},
                maxacc = {x=0, y=-9.8, z=0},
                minexptime = 0.5,
                maxexptime = 1.0,
                minsize = 1,
                maxsize = 2,
                texture = "mysponge_drip.png",
            })
        end
        local meta = core.get_meta(pos)
        if meta:get_int("is_drying") == 1 and data.steam_count > 0 then
            core.add_particlespawner({
                amount = data.steam_count,
                time = 1,
                minpos = {x=pos.x-0.3, y=pos.y, z=pos.z-0.3},
                maxpos = {x=pos.x+0.3, y=pos.y+0.3, z=pos.z+0.3},
                minvel = {x=-0.1, y=0.2, z=-0.1},
                maxvel = {x=0.1, y=2.5, z=0.1},
                minexptime = 1,
                maxexptime = 2,
                minsize = 0.5,
                maxsize = 2,
                texture = "mysponge_evap.png",
            })
        end
    end,
})

core.register_node("mysponge:dried_leaves", {
    description = "Dried Leaves",
    drawtype = "allfaces_optional",
    tiles = {"default_leaves.png^[colorize:#5C4033:120"},
    paramtype = "light",
    groups = {snappy = 3, flammable = 2, leaves = 1},
})

if core.get_modpath("lucky_block") then
	lucky_block:add_blocks({
		{"nod", "mysponge:sponge_dry", 2},
		{"nod", "mysponge:sponge_soaked", 2},
	})
end
