local S = core.get_translator("eb_eyeballs")

local DEFAULT_MOBILE_EYEBALL_SPEED = 2

eb_eyeballs.eyeball_entities = {}

local register_eyeball_class = function(classname, def)
	-- Closed static eyeball
	core.register_node("eb_eyeballs:static_"..classname.."_closed", {
		description = S("@1 (closed)", def.description),
		paramtype2 = "facedir",
		drawtype = "mesh",
		mesh = "eb_eyeballs_eyeball.gltf",
		tiles = { "eb_eyeballs_eyeball_"..classname.."_closed.png" },
		walkable = false,
		groups = { eyeball = 1, ["eyeball_"..classname] = 1, editor_breakable = 1, receiver = 1 },
		paramtype = "light",
		sunlight_propagates = true,
		_eb_eyeball_open = "eb_eyeballs:static_"..classname.."_open",
		_eb_eyeball_closed = "eb_eyeballs:static_"..classname.."_closed",
		_eb_toggle = function(pos)
			local node = core.get_node(pos)
			node.name = "eb_eyeballs:static_"..classname.."_open"
			core.swap_node(pos, node)
			eb_eyeballs.activate_eyeball(pos)
			core.sound_play({name="eb_eyeballs_eyeball_open", gain=1.0}, {pos=pos}, true)
		end,
		collision_box = { type = "fixed", fixed = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4 }},
		selection_box = { type = "fixed", fixed = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4 }},
	})

	-- Open static eyeball
	core.register_node("eb_eyeballs:static_"..classname.."_open", {
		description = S("@1 (open)", def.description),
		paramtype2 = "facedir",
		drawtype = "mesh",
		mesh = "eb_eyeballs_eyeball.gltf",
		tiles = { "eb_eyeballs_eyeball_"..classname.."_open.png" },
		walkable = false,
		groups = { eyeball = 2, ["eyeball_"..classname] = 1, editor_breakable = 1, receiver = 1 },
		paramtype = "light",
		sunlight_propagates = true,
		_eb_eyeball_open = "eb_eyeballs:static_"..classname.."_open",
		_eb_eyeball_closed = "eb_eyeballs:static_"..classname.."_closed",
		_eb_toggle = function(pos)
			local node = core.get_node(pos)
			node.name = "eb_eyeballs:static_"..classname.."_closed"
			core.swap_node(pos, node)
			eb_eyeballs.deactivate_eyeball(pos)
		end,
		collision_box = { type = "fixed", fixed = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4 }},
		selection_box = { type = "fixed", fixed = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4 }},
		_eb_sound_see = def.sound_see,
	})

	core.register_node("eb_eyeballs:static_"..classname.."_open_seeing", {
		description = S("@1 (open, seeing)", def.description),
		paramtype2 = "facedir",
		drawtype = "mesh",
		mesh = "eb_eyeballs_eyeball.gltf",
		tiles = { "eb_eyeballs_eyeball_"..classname.."_open_seeing.png" },
		walkable = false,
		groups = { eyeball = 3, ["eyeball_"..classname] = 1, editor_breakable = 1 },
		paramtype = "light",
		sunlight_propagates = true,
		_eb_eyeball_open = "eb_eyeballs:static_"..classname.."_open",
		_eb_eyeball_closed = "eb_eyeballs:static_"..classname.."_closed",
		_eb_toggle = function(pos)
			local node = core.get_node(pos)
			node.name = "eb_eyeballs:static_"..classname.."_closed"
			core.swap_node(pos, node)
			eb_eyeballs.deactivate_eyeball(pos)
		end,
		collision_box = { type = "fixed", fixed = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4 }},
		selection_box = { type = "fixed", fixed = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4 }},
		_eb_sound_unsee = def.sound_unsee,
	})

	-- Mobile eyeballs
	core.register_entity("eb_eyeballs:mobile_"..classname, {
		initial_properties = {
			visual = "mesh",
			mesh = "eb_eyeballs_eyeball.gltf",
			static_save = false,
			physical = false,
			collide_with_objects = false,
			collisionbox = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4 },
			selectionbox = { -0.4, -0.4, -0.4, 0.4, 0.4, 0.4, rotate = true },
			textures = { "eb_eyeballs_eyeball_"..classname.."_closed.png" },
		},
		_path = nil,
		_path_active = false,
		_path_next_waypoint = 1,
		_start_pos = nil,
		_state = eb_eyeballs.MOBILE_EYEBALL_STATE_CLOSED,
		_eye_id = nil,
		_autorot = false,

		on_activate = function(self)
			self.object:set_armor_groups({immortal=1})
			self._start_pos = self.object:get_pos()
			eb_eyeballs.activate_eyeball(self)
		end,
		on_deactivate = function(self)
			eb_eyeballs.deactivate_eyeball(self)
		end,
		_set_path = function(self, path)
			self._path = { waypoints = {} }
			for w=1, #path.waypoints do
				local wp = vector.add(self._start_pos, path.waypoints[w])
				table.insert(self._path.waypoints, wp)
			end
			if path.speed then
				self._path.speed = path.speed
			end
		end,
		_activate_path = function(self)
			self._path_active = true
		end,
		_deactivate_path = function(self)
			self._path_active = false
		end,
		_toggle_path = function(self)
			self._path_active = not self._path_active
		end,
		_activate_autorot = function(self)
			self._autorot = true
		end,
		_deactivate_autorot = function(self)
			self._autorot = true
		end,
		_set_eye_id = function(self, eye_id)
			self._eye_id = eye_id
		end,
		_set_state = function(self, state)
			if state == eb_eyeballs.MOBILE_EYEBALL_STATE_CLOSED then
				local textures = { "eb_eyeballs_eyeball_"..classname.."_closed.png" }
				self.object:set_properties({textures=textures})
				self._state = state
			elseif state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN then
				local textures = { "eb_eyeballs_eyeball_"..classname.."_open.png" }
				self.object:set_properties({textures=textures})
				if def.sound_unsee and self._state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN_SEEING then
					local pos = self.object:get_pos()
					core.sound_play({name=def.sound_unsee, gain=1.0}, {pos=pos}, true)
				end
				self._state = state
			elseif state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN_SEEING then
				local textures = { "eb_eyeballs_eyeball_"..classname.."_open_seeing.png" }
				self.object:set_properties({textures=textures})
				if def.sound_see and self._state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN then
					local pos = self.object:get_pos()
					core.sound_play({name=def.sound_see, gain=0.7}, {pos=pos}, true)
				end
				self._state = state
			else
				core.log("error", "[eb_eyeballs] _set_state called with invalid state for mobile eyeball at "..core.pos_to_string(self.object:get_pos(), 1))
			end
		end,
		_toggle = function(self)
			if self._state == eb_eyeballs.MOBILE_EYEBALL_STATE_CLOSED then
				local pos = self.object:get_pos()
				core.add_particlespawner({
					amount = 24,
					time = 0.01,
					texture = "eb_eyeballs_closed_break_particle.png",
					vel = {
						min = vector.new(-1.5, -1.5, -1.5),
						max = vector.new(1.5, 3, 1.5),
					},
					acc = vector.new(0, -5, 0),
					size = { min = 0.8, max = 1.7 },
					expirationtime = { min = 0.7, max = 0.8 },
					pos = {
						min = vector.offset(pos, -0.3, -0.3, -0.3),
						max = vector.offset(pos, 0.3, 0.3, 0.3),
					},
				})
				self:_set_state(eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN)
				core.sound_play({name="eb_eyeballs_eyeball_open", gain=1.0}, {pos=self.object:get_pos()}, true)
			elseif self._state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN or self._state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN_SEEING then
				self:_set_state(eb_eyeballs.MOBILE_EYEBALL_STATE_CLOSED)
			else
				core.log("error", "[eb_eyeballs] _toggle called on mobile eyeball at "..core.pos_to_string(self.object:get_pos(), 1).." but invalid state")
			end
		end,
		on_step = function(self, dtime)
			-- Follow path
			if not self._path or not self._path_active then
				if vector.length(self.object:get_velocity()) > 0.01 then
					self.object:set_velocity(vector.zero())
				end
			else
				local opos = self.object:get_pos()
				local waypoint = self._path.waypoints[self._path_next_waypoint]
				if vector.distance(opos, waypoint) < 0.05 then
					self._path_next_waypoint = self._path_next_waypoint + 1
					if not self._path.waypoints[self._path_next_waypoint] then
						self._path_next_waypoint = 1
					end
				end
				local wdir = vector.direction(opos, waypoint)
				local speed
				if self._path and self._path.speed then
					speed = self._path.speed
				else
					speed = DEFAULT_MOBILE_EYEBALL_SPEED
				end
				local vel = vector.multiply(wdir, speed)
				self.object:set_velocity(vel)
			end

			-- Autorot (automatic rotate to player)
			if self._autorot and (self._state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN or self._state == eb_eyeballs.MOBILE_EYEBALL_STATE_OPEN_SEEING) then
				local opos = self.object:get_pos()
				local objs = core.get_objects_inside_radius(opos, eb_eyeballs.MAX_SEE_DISTANCE)
				for o=1, #objs do
					local obj = objs[o]
					if obj:is_player() then
						local ppos = obj:get_pos()
						ppos.y = ppos.y + 1
						local dir_to_player = vector.direction(ppos, opos)
						local rot = vector.dir_to_rotation(dir_to_player)
						self.object:set_rotation(rot)
						break
					end
				end
			end
		end,
	})
	eb_eyeballs.eyeball_entities["eb_eyeballs:mobile_"..classname] = true

	-- Mobile eyeball spawner
	core.register_node("eb_eyeballs:mobile_spawner_"..classname.."_closed", {
		description = S("@1 (mobile spawner, closed)", def.description),
		walkable = false,
		drawtype = "allfaces",
		visual_scale = 0.5,
		paramtype = "light",
		sunlight_propagates = true,
		tiles = { "eb_eyeballs_spawner_"..classname.."_closed.png" },
		groups = { eyeball_mobile_spawner = 1, ["eyeball_mobile_spawner_"..classname] = 1, editor_breakable = 1 },
		_eb_spawned_entity = "eb_eyeballs:mobile_"..classname,
	})
	core.register_node("eb_eyeballs:mobile_spawner_"..classname.."_open", {
		description = S("@1 (mobile spawner, open)", def.description),
		walkable = false,
		drawtype = "allfaces",
		visual_scale = 0.5,
		paramtype = "light",
		sunlight_propagates = true,
		tiles = { "eb_eyeballs_spawner_"..classname.."_open.png" },
		groups = { eyeball_mobile_spawner = 2, ["eyeball_mobile_spawner_"..classname] = 1, editor_breakable = 1 },
		_eb_spawned_entity = "eb_eyeballs:mobile_"..classname,
	})
end

register_eyeball_class("good", {description=S("Good Eyeball")})
register_eyeball_class("evil", {description=S("Evil Eyeball"), sound_see="eb_eyeballs_eyeball_evil_see", sound_unsee="eb_eyeballs_eyeball_evil_unsee"})

