--[[ nodes.lua (based on nodes.lua from X Bows)
Copyright (C) 2025 SaKeL, Pixelo789

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

SPDX-License-Identifier: AGPL-3.0-or-later
--]]

local S = core.get_translator(core.get_current_modname())

core.register_node("thinkingwitharrows_bows:target", {
	description = S("Target"),
	tiles = {"thinkingwitharrows_bows_target.png"},
	stack_max = 1000,
	is_ground_content = false,
	groups = {oddly_breakable_by_hand = 2},
	on_rightclick = function(pos, node, player)
		core.sound_play("thinkingwitharrows_chime", {pitch = 2^(-2)})
		thinkingwitharrows.progress(player, 0, 0, pos)
	end,
	on_punch = function(pos, node, puncher, pointed_thing)
		local pt = pointed_thing or {}

		if pt.intersection_normal and pt.intersection_point and (puncher and puncher:is_player()) then
			local p = vector.add(pos, vector.divide(pt.intersection_normal, 1.5))
			local is_blue = false
			local is_red = false
			local is_yellow = false

			if pt.intersection_normal.x == 1 then
				local min_blue = vector.new(p.x - (1/16 * 8), p.y - (1/16 * 7), p.z - (1/16 * 7))
				local max_blue = vector.new(p.x, p.y + (1/16 * 7), p.z + (1/16 * 7))
				local min_red = vector.new(p.x - (1/16 * 8), p.y - (1/16 * 4), p.z - (1/16 * 4))
				local max_red = vector.new(p.x, p.y + (1/16 * 4), p.z + (1/16 * 4))
				local min_yellow = vector.new(p.x - (1/16 * 8), p.y - (1/16 * 1), p.z - (1/16 * 1))
				local max_yellow = vector.new(p.x, p.y + (1/16 * 1), p.z + (1/16 * 1))

				is_blue = vector.in_area(pt.intersection_point, min_blue, max_blue)
				is_red = vector.in_area(pt.intersection_point, min_red, max_red)
				is_yellow = vector.in_area(pt.intersection_point, min_yellow, max_yellow)

			elseif pt.intersection_normal.x == -1 then
				local min_blue = vector.new(p.x, p.y - (1/16 * 7), p.z - (1/16 * 7))
				local max_blue = vector.new(p.x + (1/16 * 8), p.y + (1/16 * 7), p.z + (1/16 * 7))
				local min_red = vector.new(p.x, p.y - (1/16 * 4), p.z - (1/16 * 4))
				local max_red = vector.new(p.x + (1/16 * 8), p.y + (1/16 * 4), p.z + (1/16 * 4))
				local min_yellow = vector.new(p.x, p.y - (1/16 * 1), p.z - (1/16 * 1))
				local max_yellow = vector.new(p.x + (1/16 * 8), p.y + (1/16 * 1), p.z + (1/16 * 1))

				is_blue = vector.in_area(pt.intersection_point, min_blue, max_blue)
				is_red = vector.in_area(pt.intersection_point, min_red, max_red)
				is_yellow = vector.in_area(pt.intersection_point, min_yellow, max_yellow)
			elseif pt.intersection_normal.y == 1 then
				local min_blue = vector.new(p.x - (1/16 * 7), p.y - (1/16 * 8), p.z - (1/16 * 7))
				local max_blue = vector.new(p.x + (1/16 * 7), p.y, p.z + (1/16 * 7))
				local min_red = vector.new(p.x - (1/16 * 4), p.y - (1/16 * 8), p.z - (1/16 * 4))
				local max_red = vector.new(p.x + (1/16 * 4), p.y, p.z + (1/16 * 4))
				local min_yellow = vector.new(p.x - (1/16 * 1), p.y - (1/16 * 8), p.z - (1/16 * 1))
				local max_yellow = vector.new(p.x + (1/16 * 1), p.y, p.z + (1/16 * 1))

				is_blue = vector.in_area(pt.intersection_point, min_blue, max_blue)
				is_red = vector.in_area(pt.intersection_point, min_red, max_red)
				is_yellow = vector.in_area(pt.intersection_point, min_yellow, max_yellow)
			elseif pt.intersection_normal.y == -1 then
				local min_blue = vector.new(p.x - (1/16 * 7), p.y, p.z - (1/16 * 7))
				local max_blue = vector.new(p.x + (1/16 * 7), p.y + (1/16 * 8), p.z + (1/16 * 7))
				local min_red = vector.new(p.x - (1/16 * 4), p.y, p.z - (1/16 * 4))
				local max_red = vector.new(p.x + (1/16 * 4), p.y + (1/16 * 8), p.z + (1/16 * 4))
				local min_yellow = vector.new(p.x - (1/16 * 1), p.y, p.z - (1/16 * 1))
				local max_yellow = vector.new(p.x + (1/16 * 1), p.y + (1/16 * 8), p.z + (1/16 * 1))

				is_blue = vector.in_area(pt.intersection_point, min_blue, max_blue)
				is_red = vector.in_area(pt.intersection_point, min_red, max_red)
				is_yellow = vector.in_area(pt.intersection_point, min_yellow, max_yellow)
			elseif pt.intersection_normal.z == 1 then
				local min_blue = vector.new(p.x - (1/16 * 7), p.y - (1/16 * 7), p.z - (1/16 * 8))
				local max_blue = vector.new(p.x + (1/16 * 7), p.y + (1/16 * 7), p.z)
				local min_red = vector.new(p.x - (1/16 * 4), p.y - (1/16 * 4), p.z - (1/16 * 8))
				local max_red = vector.new(p.x + (1/16 * 4), p.y + (1/16 * 4), p.z)
				local min_yellow = vector.new(p.x - (1/16 * 1), p.y - (1/16 * 1), p.z - (1/16 * 8))
				local max_yellow = vector.new(p.x + (1/16 * 1), p.y + (1/16 * 1), p.z)

				is_blue = vector.in_area(pt.intersection_point, min_blue, max_blue)
				is_red = vector.in_area(pt.intersection_point, min_red, max_red)
				is_yellow = vector.in_area(pt.intersection_point, min_yellow, max_yellow)
			elseif pt.intersection_normal.z == -1 then
				local min_blue = vector.new(p.x - (1/16 * 7), p.y - (1/16 * 7), p.z)
				local max_blue = vector.new(p.x + (1/16 * 7), p.y + (1/16 * 7), p.z + (1/16 * 8))
				local min_red = vector.new(p.x - (1/16 * 4), p.y - (1/16 * 4), p.z)
				local max_red = vector.new(p.x + (1/16 * 4), p.y + (1/16 * 4), p.z + (1/16 * 8))
				local min_yellow = vector.new(p.x - (1/16 * 1), p.y - (1/16 * 1), p.z)
				local max_yellow = vector.new(p.x + (1/16 * 1), p.y + (1/16 * 1), p.z + (1/16 * 8))

				is_blue = vector.in_area(pt.intersection_point, min_blue, max_blue)
				is_red = vector.in_area(pt.intersection_point, min_red, max_red)
				is_yellow = vector.in_area(pt.intersection_point, min_yellow, max_yellow)
			end

			-- black
			local color = "#000000"
			local w = 16
			local h = 16
			local pitch = 2^(-2) -- two octaves lower
			local area = 1

			if is_yellow then
				color = "#FBF236"
				w = 2
				h = 2
				pitch = 2^(-1) -- one octave lower
				area = 4
			elseif is_red then
				color = "#D95763"
				w = 8
				h = 8
				area = 3
			elseif is_blue then
				color = "#639BFF"
				w = 14
				h = 14
				area = 2
			end

			-- top vertical
			local image = "[combine:16x16:" .. (16 - w) / 2 .. "," .. (16 - h) / 2
				.. "=[combine\\:".. w .. "x1\\^[noalpha\\^[colorize\\:" .. color .. "\\:255"
			-- bottom vertical
			image = image .."^[combine:16x16:" .. (16 - w) / 2 .. "," .. h + ((16 - h) / 2) - 1
				.. "=[combine\\:".. w .. "x1\\^[noalpha\\^[colorize\\:" .. color .. "\\:255"
			-- left horizontal
			image = image .."^[combine:16x16:" .. (16 - w) / 2 .. "," .. (16 - h) / 2
				.. "=[combine\\:1x" .. h .. "\\^[noalpha\\^[colorize\\:" .. color .. "\\:255"
			-- right horizontal
			image = image .."^[combine:16x16:".. w + ((16 - w) / 2) - 1 .. "," .. (16 - h) / 2
				.. "=[combine\\:1x" .. h .. "\\^[noalpha\\^[colorize\\:" .. color .. "\\:255"

			core.add_particle({
				pos = p,
				velocity = pt.intersection_normal,
				acceleration = vector.multiply(vector.multiply(pt.intersection_normal, -1), 2),
				expirationtime = 1,
				size = 10,
				texture = {
					name = image,
					alpha_tween = {
						1, 0.25,
						style = "fwd",
						reps = 1
					}
				},
				glow = 14
			})

			-- play a chime
			core.sound_play("thinkingwitharrows_chime", {pitch = pitch})

			local player_pos = puncher:get_pos()
			local player_props = puncher:get_properties()
			local eye_height = player_props.eye_height or 1.625
			local look_dir = puncher:get_look_dir()
			local distance = vector.distance(pt.intersection_point, player_pos)

			thinkingwitharrows.progress(puncher, area, distance, pos)
		end
	end
})


-- Block that gives a bow when clicked
core.register_node("thinkingwitharrows_bows:bow_block", {
	description = S("Block to obtain bow"),
	tiles = {"thinkingwitharrows_bows_bow_block.png"},
	stack_max = 1000,
	groups = {oddly_breakable_by_hand = 2},
	on_rightclick = function(pos, node, player)
		core.sound_play("thinkingwitharrows_woosh", {start_time = 0.05})

		local inv = player:get_inventory()

		-- add bow
		local stack = ItemStack({name = "thinkingwitharrows_bows:bow", count = 1})
		-- FIXME: for whatever reason, the item doesn't get added if that slot is currently being focused, so we add two
		inv:add_item("main", stack)
		inv:add_item("main", stack)

		-- add arrows
		thinkingwitharrows_bows.set_arrows(player, 5)

		-- start showing bow HUD
		player:get_meta():set_int("show_bow_hud", 1)
		XBowsQuiver:udate_or_create_hud(player, inv:get_list("x_bows:arrow_inv"))

		core.remove_node(pos)
	end,
})


local function arrow_block_interact(player, is_shot)
	local inv = player:get_inventory()

	-- add arrows
	local old_stack = inv:get_stack("x_bows:arrow_inv", 1)
	local old_count = old_stack:get_count()
	if old_count == 0 or old_count == nil then
		core.sound_play("thinkingwitharrows_woosh", {start_time = 0.05})
		thinkingwitharrows_bows.add_arrows(player, 5, false)
	elseif old_count < 5 and thinkingwitharrows.difficulty == 0 then
		core.sound_play("thinkingwitharrows_woosh", {start_time = 0.05})
		thinkingwitharrows_bows.set_arrows(player, 5)
	else
		core.sound_play("thinkingwitharrows_error")
	end
end

-- Block that gives arrows when clicked
core.register_node("thinkingwitharrows_bows:arrow_block", {
	description = S("Block to obtain arrows"),
	tiles = {"thinkingwitharrows_bows_arrow_block.png"},
	stack_max = 1000,
	groups = {oddly_breakable_by_hand = 2},
	on_rightclick = function(pos, node, player)
		arrow_block_interact(player, false)
	end,
	on_punch = function(pos, node, puncher, pointed_thing)
		local pt = pointed_thing or {}

		if pt.intersection_normal and pt.intersection_point and (puncher and puncher:is_player()) then
			arrow_block_interact(puncher, true)
		end
	end
})
