local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)

mcl_flowers = {}
mcl_flowers.registered_simple_flowers = {}
-- Simple flower template
local smallflowerlongdesc = S("This is a small flower. Small flowers are mainly used for dye production and can also be potted.")
mcl_flowers.plant_usage_help = S("It can only be placed on a block on which it would also survive.")

function mcl_flowers.on_bone_meal(_, _, _ , pos, n)
	if n.name == "mcl_flowers:rose_bush" or n.name == "mcl_flowers:rose_bush_top" then
		minetest.add_item(pos, "mcl_flowers:rose_bush")
		return true
	elseif n.name == "mcl_flowers:peony" or n.name == "mcl_flowers:peony_top" then
		minetest.add_item(pos, "mcl_flowers:peony")
		return true
	elseif n.name == "mcl_flowers:lilac" or n.name == "mcl_flowers:lilac_top" then
		minetest.add_item(pos, "mcl_flowers:lilac")
		return true
	elseif n.name == "mcl_flowers:sunflower" or n.name == "mcl_flowers:sunflower_top" then
		minetest.add_item(pos, "mcl_flowers:sunflower")
		return true
	elseif n.name == "mcl_flowers:tallgrass" then
		-- Tall Grass: Grow into double tallgrass
		local toppos = { x=pos.x, y=pos.y+1, z=pos.z }
		local topnode = minetest.get_node(toppos)
		if minetest.registered_nodes[topnode.name].buildable_to then
			minetest.set_node(pos, { name = "mcl_flowers:double_grass", param2 = n.param2 })
			minetest.set_node(toppos, { name = "mcl_flowers:double_grass_top", param2 = n.param2 })
			return true
		end
	elseif n.name == "mcl_flowers:fern" then
		-- Fern: Grow into large fern
		local toppos = { x=pos.x, y=pos.y+1, z=pos.z }
		local topnode = minetest.get_node(toppos)
		if minetest.registered_nodes[topnode.name].buildable_to then
			minetest.set_node(pos, { name = "mcl_flowers:double_fern", param2 = n.param2 })
			minetest.set_node(toppos, { name = "mcl_flowers:double_fern_top", param2 = n.param2 })
			return true
		end
	end
	return false
end

local scan_area = 9
local spawn_on = { "mcl_core:dirt", "group:grass_block" }

function mcl_flowers.on_bone_meal_simple(_, _, _, pos, n)
	if n.name ~= "mcl_flowers:wither_rose" then
		local nn = minetest.find_nodes_in_area_under_air(
			vector.offset(pos, -scan_area, -3, -scan_area),
			vector.offset(pos, scan_area, 3, scan_area),
			spawn_on
		)

		local any_placed = false
		if next(nn) ~= nil then
			table.shuffle(nn)
			for i = 1, math.random(1, math.min(14, #nn)) do
				if minetest.add_node(vector.offset(nn[i], 0, 1, 0), { name = n.name }) then
					any_placed = true
				end
			end
			return any_placed
		end
	end

	return false
end

function mcl_flowers.get_palette_color_from_pos(pos)
	local biome_data = minetest.get_biome_data(pos)
	local index = 0
	if biome_data then
		local biome = biome_data.biome
		local biome_name = minetest.get_biome_name(biome)
		local reg_biome = minetest.registered_biomes[biome_name]
		if reg_biome then
			index = reg_biome._mcl_palette_index
		end
	end
	return index
end

-- on_place function for flowers
mcl_flowers.on_place_flower = mcl_util.generate_on_place_plant_function(function(pos, _, itemstack)
	local below = {x=pos.x, y=pos.y-1, z=pos.z}
	local soil_node = minetest.get_node_or_nil(below)
	if not soil_node then return false end

	local has_palette = minetest.registered_nodes[itemstack:get_name()].palette ~= nil
	local colorize
	if has_palette then
		colorize = mcl_flowers.get_palette_color_from_pos(pos)
	end
	if not colorize then
		colorize = 0
	end

--[[	Placement requirements:
	* Dirt, grass or moss block
	* If not flower, also allowed on podzol and coarse dirt
	* Light level >= 8 at any time or exposed to sunlight at day
]]
	local light_night = minetest.get_node_light(pos, 0.0)
	local light_day = minetest.get_node_light(pos, 0.5)
	local light_ok = false
	if (light_night and light_night >= 8) or (light_day and light_day >= minetest.LIGHT_MAX) then
		light_ok = true
	end
	if itemstack:get_name() == "mcl_flowers:wither_rose" and (  minetest.get_item_group(soil_node.name, "grass_block") > 0 or soil_node.name == "mcl_core:dirt" or soil_node.name == "mcl_core:coarse_dirt" or soil_node.name == "mcl_lush_caves:moss" or soil_node.name == "mcl_nether:netherrack" or minetest.get_item_group(soil_node.name, "soul_block") > 0  ) then
		return true,colorize
	end
	local is_flower = minetest.get_item_group(itemstack:get_name(), "flower") == 1
	local ok = (soil_node.name == "mcl_core:dirt" or minetest.get_item_group(soil_node.name, "grass_block") == 1 or soil_node.name == "mcl_lush_caves:moss" or (not is_flower and (soil_node.name == "mcl_core:coarse_dirt" or soil_node.name == "mcl_core:podzol" or soil_node.name == "mcl_core:podzol_snow"))) and light_ok
	return ok, colorize
end)

function mcl_flowers.register_simple_flower(name, def)
	local newname = "mcl_flowers:"..name
	if not def._mcl_silk_touch_drop then def._mcl_silk_touch_drop = nil end
	if not def.drop then def.drop = newname end
	mcl_flowers.registered_simple_flowers[newname] = {
		name=name,
		desc=def.desc,
		image=def.image,
		simple_selection_box=def.simple_selection_box,
	}
	minetest.register_node(":"..newname, {
		description = def.desc,
		_doc_items_longdesc = smallflowerlongdesc,
		_doc_items_usagehelp = mcl_flowers.plant_usage_help,
		drawtype = "plantlike",
		waving = 1,
		tiles = { def.image },
		inventory_image = def.image,
		wield_image = def.image,
		sunlight_propagates = true,
		paramtype = "light",
		walkable = false,
		drop = def.drop,
		groups = {
			attached_node = 1, deco_block = 1, dig_by_piston = 1, dig_immediate = 3,
			dig_by_water = 1, destroy_by_lava_flow = 1, enderman_takable = 1,
			plant = 1, flower = 1, place_flowerlike = 1, non_mycelium_plant = 1,
			flammable = 2, fire_encouragement = 60, fire_flammability = 100,
			compostability = 65, unsticky = 1
		},
		sounds = mcl_sounds.node_sound_leaves_defaults(),
		node_placement_prediction = "",
		on_place = mcl_flowers.on_place_flower,
		selection_box = {
			type = "fixed",
			fixed = def.selection_box,
		},
		_mcl_silk_touch_drop = def._mcl_silk_touch_drop,
		_on_bone_meal = mcl_flowers.on_bone_meal_simple,
	})
	if minetest.get_modpath("mcl_flowerpots") then
		if def.potted then--TODO not sure if this check is necessary
			mcl_flowerpots.register_potted_flower(newname, {
				name = name,
				desc = def.desc,
				image = def.image,
			})
		end
	end
end

local tpl_large_plant_top = {
	drawtype = "plantlike",
	_doc_items_create_entry = true,
	_doc_items_usagehelp = mcl_flowers.plant_usage_help,
	sunlight_propagates = true,
	paramtype = "light",
	walkable = false,
	sounds = mcl_sounds.node_sound_leaves_defaults(),
	_on_bone_meal = mcl_flowers.on_bone_meal,
}

local tpl_large_plant_bottom = table.merge(tpl_large_plant_top, {
	groups = {
		attached_node = 1, deco_block = 1,
		dig_by_water = 1, destroy_by_lava_flow = 1, dig_by_piston = 1,
		flammable = 2, fire_encouragement = 60, fire_flammability = 100,
		plant = 1, double_plant = 1, non_mycelium_plant = 1, flower = 1,
		compostability = 65, unsticky = 1
	},
	on_place = function(itemstack, placer, pointed_thing)
		-- We can only place on nodes
		if pointed_thing.type ~= "node" then
			return
		end

		local itemstring = itemstack:get_name()

		-- Call on_rightclick if the pointed node defines it
		if placer and not placer:get_player_control().sneak then
			local rc = mcl_util.call_on_rightclick(itemstack, placer, pointed_thing)
			if rc ~= nil then return rc end --check for nil explicitly to determine if on_rightclick existed
		end

		-- Check for a floor and a space of 1×2×1
		local ptu_node = minetest.get_node(pointed_thing.under)
		local bottom
		if not minetest.registered_nodes[ptu_node.name] then
			return itemstack
		end
		if minetest.registered_nodes[ptu_node.name].buildable_to then
			bottom = pointed_thing.under
		else
			bottom = pointed_thing.above
		end
		if not minetest.registered_nodes[minetest.get_node(bottom).name] then
			return itemstack
		end
		local top = { x = bottom.x, y = bottom.y + 1, z = bottom.z }
		local bottom_buildable = minetest.registered_nodes[minetest.get_node(bottom).name].buildable_to
		local top_buildable = minetest.registered_nodes[minetest.get_node(top).name].buildable_to
		local floor = minetest.get_node({x=bottom.x, y=bottom.y-1, z=bottom.z})
		if not minetest.registered_nodes[floor.name] then
			return itemstack
		end

		local light_night = minetest.get_node_light(bottom, 0.0)
		local light_day = minetest.get_node_light(bottom, 0.5)
		local light_ok = false
		if (light_night and light_night >= 8) or (light_day and light_day >= minetest.LIGHT_MAX) then
			light_ok = true
		end
		local is_flower = minetest.get_item_group(floor.name, "flower") > 0

		-- Placement rules:
		-- * Allowed on dirt, grass or moss block
		-- * If not a flower, also allowed on podzol and coarse dirt
		-- * Only with light level >= 8
		-- * Only if two enough space
		if (floor.name == "mcl_core:dirt" or minetest.get_item_group(floor.name, "grass_block") == 1 or floor.name == "mcl_lush_caves:moss" or (not is_flower and (floor.name == "mcl_core:coarse_dirt" or floor.name == "mcl_core:podzol" or floor.name == "mcl_core:podzol_snow"))) and bottom_buildable and top_buildable and light_ok then
			local param2
			local def = minetest.registered_nodes[floor.name]
			if def and def.paramtype2 == "color" then
				param2 = mcl_flowers.get_palette_color_from_pos(bottom)
			end
			-- Success! We can now place the flower
			minetest.sound_play(minetest.registered_nodes[itemstring].sounds.place, {pos = bottom, gain=1}, true)
			minetest.set_node(bottom, {name=itemstring, param2=param2})
			minetest.set_node(top, {name=itemstring.."_top", param2=param2})
			if not minetest.is_creative_enabled(placer:get_player_name()) then
				itemstack:take_item()
			end
		end
		return itemstack
	end,
	after_destruct = function(pos, oldnode)
		-- Remove top half of flower (if it exists)
		local bottom = pos
		local top = { x = bottom.x, y = bottom.y + 1, z = bottom.z }
		if minetest.get_node(bottom).name ~= oldnode.name and minetest.get_node(top).name == oldnode.name.."_top" then
			minetest.remove_node(top)
		end
	end,
})

function mcl_flowers.add_large_plant(name, def)
	def.bottom =  def.bottom or {}
	def.bottom.groups = table.merge(tpl_large_plant_bottom.groups, def.bottom.groups or {})
	def.top = def.top or {}
	def.top.groups = def.top.groups or {}

	if def.is_flower then
		table.update(def.bottom.groups, { flower = 1, place_flowerlike = 1, dig_immediate = 3 })
	else
		table.update(def.bottom.groups, { place_flowerlike = 2, handy = 1, shearsy = 1 })
	end

	table.update(def.top.groups, { not_in_creative_inventory=1, handy = 1, shearsy = 1, double_plant=2, attached_node=nil })

	if def.grass_color then
		def.bottom.paramtype2 = "color"
		def.top.paramtype2 = "color"
		def.bottom.palette = "mcl_core_palette_grass.png"
		def.top.palette = "mcl_core_palette_grass.png"
	end

	if def.bottom._doc_items_longdesc == nil and def.longdesc == nil then
		def.bottom.groups.not_in_creative_inventory = 1
		def.bottom._doc_items_create_entry = false
	end

	local selbox_radius = def.selbox_radius or 0.5
	local selbox_top_height = def.selbox_top_height or 0.5
	local inv_img = def.inv_img or def.bottom.inventory_image or (def.tiles_top and def.tiles_top[1]) or (def.top.tiles and def.top.tiles[1])
	-- Bottom
	minetest.register_node(":mcl_flowers:"..name, table.merge(tpl_large_plant_bottom,{
		description = def.desc,
		_doc_items_longdesc = def.longdesc,
		tiles = def.tiles_bottom,
		node_placement_prediction = "",
		inventory_image = inv_img,
		wield_image = inv_img,
		drop = "mcl_flowers:"..name,
		selection_box = {
			type = "fixed",
			fixed = { -selbox_radius, -0.5, -selbox_radius, selbox_radius, 0.5, selbox_radius },
		},
	}, def.bottom or {}))

	-- Top
	minetest.register_node(":mcl_flowers:"..name.."_top", table.merge(tpl_large_plant_top, {
		description = S("@1 (Top Part)", def.desc or def.bottom.description or name),
		_doc_items_create_entry = false,
		selection_box = {
			type = "fixed",
			fixed = { -selbox_radius, -0.5, -selbox_radius, selbox_radius, selbox_top_height, selbox_radius },
		},
		tiles = def.tiles_top,
		drop = def.bottom.drop or ( "mcl_flowers:"..name ),
		_mcl_shears_drop = def.bottom._mcl_shears_drop,
		_mcl_fortune_drop = def.bottom._mcl_fortune_drop,
		_mcl_baseitem = "mcl_flowers:"..name,
		after_destruct = function(pos, _)
			-- Remove bottom half of flower (if it exists)
			local top = pos
			local bottom = { x = top.x, y = top.y - 1, z = top.z }
			if minetest.get_node(top).name ~= "mcl_flowers:"..name.."_top" and minetest.get_node(bottom).name == "mcl_flowers:"..name then
				minetest.remove_node(bottom)
			end
		end,
	}, def.top))

	if def.bottom._doc_items_longdesc then
		doc.add_entry_alias("nodes", "mcl_flowers:"..name, "nodes", "mcl_flowers:"..name.."_top")
		-- If no longdesc, help alias must be added manually
	end

end

minetest.register_abm({--here
	label = "Pop out flowers",
	nodenames = {"group:flower"},
	interval = 12,
	chance = 2,
	action = function(pos, node)
		-- Ignore the upper part of double plants
		if minetest.get_item_group(node.name, "double_plant") == 2 then
			return
		end
		local below = minetest.get_node_or_nil({x=pos.x, y=pos.y-1, z=pos.z})
		if not below then
			return
		end
		-- Pop out flower if not on dirt, grass block or too low brightness
		if (minetest.get_item_group(below.name, "soil") ~= 1 and below.name ~= "mcl_core:dirt" and minetest.get_item_group(below.name, "grass_block") ~= 1 and below.name ~= "mcl_lush_caves:moss") or (minetest.get_node_light(pos, 0.5) < 8) then--added check for "soil"
			minetest.dig_node(pos)
			return
		end
	end,
})

-- Legacy support
minetest.register_alias("mcl_core:tallgrass", "mcl_flowers:tallgrass")

-- mcimport support: re-adds missing double_plant tops in mcimported worlds.
local mg_name = minetest.get_mapgen_setting("mg_name")
local mod_mcimport = minetest.get_modpath("mcimport")

if mod_mcimport and mg_name == "singlenode" then
	local flowernames = { "peony", "rose_bush", "lilac", "sunflower", "double_fern", "double_grass" }

	minetest.register_lbm({
		label = "Add double plant tops.",
		name = "mcl_flowers:double_plant_topper",
		run_at_every_load = true,
		nodenames = { "mcl_flowers:peony", "mcl_flowers:rose_bush", "mcl_flowers:lilac", "mcl_flowers:sunflower", "mcl_flowers:double_fern", "mcl_flowers:double_grass" },
		action = function(pos, node)
			for c = 1, 6 do
				local flowername = flowernames[c]
				local bottom = pos
				local top = { x = bottom.x, y = bottom.y + 1, z = bottom.z }
				if node.name == "mcl_flowers:"..flowername then
					minetest.set_node(top, {name = "mcl_flowers:"..flowername.."_top"})
				end
			end
		end,
	})
end

dofile(modpath.."/register.lua")
