class_name Trap extends Area3D

enum Type{
	BOMB,
	MINE,
	GAS,
	FORCE_PANEL,
	SWITCH,
	PITFALL
}

const range_shapes : Dictionary = {
	Trap.Type.BOMB : 		Vector3(5,1,5),
	Trap.Type.GAS : 			Vector3(1,1,1),
	Trap.Type.PITFALL : 		Vector3(1,1,1),
	Trap.Type.FORCE_PANEL : Vector3(1,1,1),
	Trap.Type.SWITCH : 		Vector3(3,1,3),
	Trap.Type.MINE : 		Vector3(5,1,5),
}
const trap_icons : Dictionary = {
	Trap.Type.BOMB : 		preload("res://visuals/images/icons/t-bomb.png"),
	Trap.Type.GAS : 		preload("res://visuals/images/icons/t-gas.png"),
	Trap.Type.PITFALL : 	preload("res://visuals/images/icons/t-pitfall.png"),
	Trap.Type.FORCE_PANEL : preload("res://visuals/images/icons/t-force_panel.png"),
	Trap.Type.SWITCH : 		preload("res://visuals/images/icons/t-switch.png"),
	Trap.Type.MINE : 		preload("res://visuals/images/icons/t-mine.png"),
}

const bomb_explosion_template = preload("res://templates/explosion.tscn")
const mine_explosion_template = preload("res://templates/explosion.tscn")
const pitfall_template = preload("res://templates/pitfall.tscn")
const switch_explosion_template = preload("res://templates/explosion.tscn")
const gas_emitter_template = preload("res://templates/gas_emitter.tscn")
const force_activate_sound = preload("res://audio/sounds/TomWinandySFX_UI_ScifiTech_Start_06.wav")

@onready var range_area : Area3D = %RangeArea
@onready var range_shape : BoxShape3D = %RangeShape.shape
@onready var model : MeshInstance3D = %Model
@onready var icon : Sprite3D  = %Icon
@onready var force_strip : Sprite3D = %ForceStrip
@onready var material : StandardMaterial3D = model.get_surface_override_material(0)
@onready var reveal_timer : Timer = %RevealTimer
@onready var activation_timer : Timer = %ActivationTimer

var type : Type
var square : Vector3i
var trap_owner : int
var direction : Vector3

var expended : bool = false
var disarming : bool
var disarm_id : int

var delayed_trigger_tween : Tween = null

var damage : int = 10

var just_revealed : bool = false


signal removed(type : Trap.Type)
signal disarmed(type : Trap.Type)
signal activated(type : Trap.Type)

func setup(type : Type, direction : Vector3, trap_owner : int) -> void:
	self.type = type
	self.trap_owner = trap_owner
	if type == Type.FORCE_PANEL:
		var r : float = atan2(direction.z, direction.x)
		var cardinal : float = roundi(r * 2 / PI) * PI / 2
		self.direction = Vector3(cos(cardinal), 0, sin(cardinal))

func remove() -> void:
	removed.emit(type)
	queue_free()

func disarm() -> void:
	disarmed.emit(type)
	queue_free()

func reveal() -> void:
	if model.visible:
		return
	model.visible = true
	reveal_timer.start(5)
	just_revealed = true

func is_just_revealed() -> bool:
	return just_revealed
	
func is_revealed() -> bool:
	return model.visible

func _on_reveal_timeout() -> void:
	if Game.level.is_square_detected(square) or disarming:
		reveal_timer.start(5)
	else:
		model.visible = false

func _ready() -> void:
	var owns_trap = trap_owner == Multiplayer.id
	icon.texture = trap_icons[type]
	model.visible = owns_trap
	icon.visible = owns_trap
	range_shape.size = range_shapes[type]
	material.albedo_color = Color.YELLOW if owns_trap else Color.RED
	match(type):
		Type.BOMB:
			damage = 15
		Type.MINE:
			damage = 10
		Type.SWITCH:
			damage = 5
		Type.GAS:
			activation_timer.start()
		Type.FORCE_PANEL:
			var r : float = atan2(direction.z, -direction.x) + PI/2
			force_strip.rotate_y(r)
			force_strip.visible = owns_trap

func _process(delta: float) -> void:
	just_revealed = false

func blast(body : PawnController) -> void:
	body.hurt(damage)
	body.knockup((global_position.direction_to(body.global_position) + Vector3(0,2,0)) * 3)

func activate() -> void:
	if expended:
		return
	var explode : bool = false
	match(type):
		Type.PITFALL:
			generate_pitfall(square)
			for body in get_overlapping_bodies():
				body.start_pitfall(square, 6.0)
			#Generate the circle here
		Type.FORCE_PANEL:
			Game.oneshot(force_activate_sound)
			for body in get_overlapping_bodies():
				body.fling(direction, 5.0)
		Type.MINE:
			var exp = mine_explosion_template.instantiate()
			Game.level.add_vfx(exp, square)
			explode = true
		Type.SWITCH:
			var exp = switch_explosion_template.instantiate()
			Game.level.add_vfx(exp, square)
			explode = true
		Type.BOMB:
			var exp = bomb_explosion_template.instantiate()
			Game.level.add_vfx(exp, square)
			explode = true
		Type.GAS:
			var emitter = gas_emitter_template.instantiate()
			emitter.trap_owner = trap_owner
			emitter.square = square
			emitter.damage = 4
			Game.level.add_vfx(emitter, square)
	
	if explode:
		trigger_adjacent_bombs()
		blast_players()
	
	expended = true
	Game.level.remove_trap_square(square)
	activated.emit(type)
	queue_free()

func trigger_adjacent_bombs() -> void:
	for trap : Trap in range_area.get_overlapping_areas():
		if trap.type == Type.BOMB and trap != self:
			trap.delay_trigger()

func generate_pitfall(suqare : Vector3i) -> void:
	var pitfall = pitfall_template.instantiate()
	pitfall.duration = 6.0
	Game.level.add_vfx(pitfall, square)
	
func blast_players() -> void:
	for body in range_area.get_overlapping_bodies():
		blast(body)	

func delay_trigger() -> void:
	if delayed_trigger_tween != null:
		return
	delayed_trigger_tween = create_tween()
	delayed_trigger_tween.tween_interval(.25)
	delayed_trigger_tween.tween_callback(activate)
		

func _on_body_entered(body: Node3D) -> void:
	if type == Type.GAS or type == Type.BOMB:
		return
		
	if body.id == trap_owner:
		return
		
	if !disarming or body.id != disarm_id:
		if !body.detecting:
			activate()


func _on_activation_timer_timeout() -> void:
	activate()
