extends Node3D

const DOOR_OPEN_X := 1.154
const DOOR_CLOSED_X := 0.7
const DOOR_DEFAULT_TIME := 3.0
const DOOR_FAST_CLOSE_TIME := 1.0
const DOOR_REOPEN_TIME := 0.4
const PULSE_CLOSE_LAG_TOP := 1.0
const PULSE_CLOSE_LAG_PER_FLOOR := 0.09
const PULSE_CLOSE_LAG_MIN := 0.2
const DOORS_NEARLY_OPEN_LEAD := 0.4

var _tween: Tween = null
var _pulse_close_pending: bool = false
var _current_floor: int = EventBus.STARTING_FLOOR

func _ready():
	$ElevatorDoorRight.position = Vector3(DOOR_CLOSED_X, 0, 0)
	$ElevatorDoorLeft.position = Vector3(-DOOR_CLOSED_X, 0, 0)
	_set_door_collision(true)
	EventBus.doors_opened.connect(_on_doors_opened)
	EventBus.doors_closed.connect(_on_doors_closed)
	EventBus.pulse_started.connect(_on_pulse_started)
	EventBus.pulse_blocked.connect(_on_pulse_blocked)
	EventBus.floor_changed.connect(func(f): _current_floor = f)

func _on_doors_opened():
	_pulse_close_pending = false
	_set_door_collision(false)
	_tween_doors(DOOR_OPEN_X, DOOR_DEFAULT_TIME)
	_tween.chain().tween_callback(func(): EventBus.doors_fully_opened.emit())
	get_tree().create_timer(DOOR_DEFAULT_TIME - DOORS_NEARLY_OPEN_LEAD, false).timeout.connect(
		func(): EventBus.doors_nearly_opened.emit(),
		CONNECT_ONE_SHOT
	)

func _on_doors_closed(fast: bool):
	_pulse_close_pending = false
	_set_door_collision(true)
	_tween_doors(DOOR_CLOSED_X, DOOR_FAST_CLOSE_TIME if fast else DOOR_DEFAULT_TIME)
	_tween.chain().tween_callback(func(): EventBus.doors_fully_closed.emit())

func _on_pulse_started(duration: float):
	_set_door_collision(true)
	_pulse_close_pending = true
	var floors_descended = EventBus.STARTING_FLOOR - _current_floor
	var lag = max(PULSE_CLOSE_LAG_MIN, PULSE_CLOSE_LAG_TOP - floors_descended * PULSE_CLOSE_LAG_PER_FLOOR)
	get_tree().create_timer(lag, false).timeout.connect(
		func():
			if not _pulse_close_pending:
				return
			if $ElevatorDoorRight.position.x < DOOR_OPEN_X - 0.001:
				_pulse_close_pending = false
				return
			_pulse_close_pending = false
			_tween_doors(DOOR_CLOSED_X, duration),
		CONNECT_ONE_SHOT
	)

func _on_pulse_blocked():
	_pulse_close_pending = false
	_set_door_collision(false)
	_tween_doors(DOOR_OPEN_X, DOOR_REOPEN_TIME)

func _set_door_collision(enabled: bool):
	$ElevatorDoorRight/CollisionShape3D.disabled = not enabled
	$ElevatorDoorLeft/CollisionShape3D.disabled = not enabled

func get_door_close_progress() -> float:
	var cur: float = $ElevatorDoorRight.position.x
	return clamp((DOOR_OPEN_X - cur) / (DOOR_OPEN_X - DOOR_CLOSED_X), 0.0, 1.0)

func _tween_doors(target_x: float, duration: float):
	if _tween:
		_tween.kill()
	_tween = create_tween()
	_tween.set_parallel(true)
	_tween.tween_property($ElevatorDoorRight, "position:x", target_x, duration)
	_tween.tween_property($ElevatorDoorLeft, "position:x", -target_x, duration)
