extends Node

const TRAIL_GHOSTS := 8
const TRAIL_SPACING := 3.0
const TRAIL_ALPHAS := [0.5, 0.42, 0.34, 0.27, 0.2, 0.14, 0.09, 0.05]
const GLOW_PADDING := Vector2(6, 6)
const GLOW_COLOR := Color(1, 0.3, 0.3, 0.35)

var pulse_speed := 80.0
var pulse_speed_initial := 80.0
var pulse_speed_per_floor := 8.0
var pulse_speed_increase := 15.0
var pulse_x := 0.0
var pulse_active := false
var pulse_gap := 1.0
var pulse_gap_decrease := 0.05
var pulse_gap_min := 0.3
var pulses_blocked := 0

var _sweep_line: ColorRect
var _target_zone: ColorRect
var _perfect_zone: ColorRect
var _screen_width: float
var _glow: ColorRect
var _trail: Array[ColorRect] = []

signal pulse_started(duration: float)
signal pulse_blocked
signal pulse_blocked_perfect
signal pulse_escaped

func configure(sweep_line: ColorRect, target_zone: ColorRect, perfect_zone: ColorRect, screen_width: float):
	_sweep_line = sweep_line
	_target_zone = target_zone
	_perfect_zone = perfect_zone
	_screen_width = screen_width
	_build_visuals()

func _build_visuals():
	var host: Control = _sweep_line.get_parent() as Control
	_glow = ColorRect.new()
	_glow.color = GLOW_COLOR
	_glow.size = Vector2(_sweep_line.size.x + GLOW_PADDING.x * 2, _sweep_line.size.y + GLOW_PADDING.y * 2)
	_glow.visible = false
	host.add_child(_glow)
	host.move_child(_glow, 0)

	for i in TRAIL_GHOSTS:
		var ghost := ColorRect.new()
		ghost.color = Color(_sweep_line.color.r, _sweep_line.color.g, _sweep_line.color.b, TRAIL_ALPHAS[i])
		ghost.size = _sweep_line.size
		ghost.visible = false
		host.add_child(ghost)
		host.move_child(ghost, 0)
		_trail.append(ghost)

func start_floor(floor_num: int):
	pulses_blocked = 0
	var floors_descended = EventBus.STARTING_FLOOR - floor_num
	pulse_speed = pulse_speed_initial + floors_descended * pulse_speed_per_floor
	pulse_gap = 1.0
	pulse_active = false

func launch():
	pulse_x = 0.0
	pulse_active = true
	_sweep_line.visible = true
	_sweep_line.position.x = 0
	_glow.visible = true
	for ghost in _trail:
		ghost.visible = true
	pulse_started.emit(_screen_width / pulse_speed)

func attempt_block() -> bool:
	if not pulse_active:
		return false
	var bz_left = _target_zone.position.x
	var bz_right = _target_zone.position.x + _target_zone.size.x
	if pulse_x >= bz_left and pulse_x <= bz_right:
		var perfect_left = bz_left + _perfect_zone.position.x
		var perfect_right = perfect_left + _perfect_zone.size.x
		var was_perfect = pulse_x >= perfect_left and pulse_x <= perfect_right
		pulse_active = false
		pulses_blocked += 1
		pulse_speed += pulse_speed_increase
		pulse_gap = max(pulse_gap - pulse_gap_decrease, pulse_gap_min)
		_hide_visuals()
		pulse_blocked.emit()
		if was_perfect:
			pulse_blocked_perfect.emit()
		return true
	else:
		pulse_active = false
		_hide_visuals()
		pulse_escaped.emit()
		return false

func get_pulse_gap() -> float:
	return pulse_gap

func stop():
	pulse_active = false
	_hide_visuals()

func _process(delta):
	if not pulse_active:
		return
	pulse_x += pulse_speed * delta
	_sweep_line.position.x = pulse_x
	_glow.position = Vector2(pulse_x - GLOW_PADDING.x, _sweep_line.position.y - GLOW_PADDING.y)
	for i in _trail.size():
		var gx = pulse_x - (i + 1) * TRAIL_SPACING
		_trail[i].visible = gx >= 0
		_trail[i].position = Vector2(gx, _sweep_line.position.y)
	if pulse_x >= _screen_width:
		pulse_active = false
		_hide_visuals()
		pulse_escaped.emit()

func _hide_visuals():
	if _sweep_line:
		_sweep_line.visible = false
	if _glow:
		_glow.visible = false
	for ghost in _trail:
		ghost.visible = false
