class_name NoteSpawner extends NoteView

signal notes_spawned(beat: float)

@export var lanes: Dictionary[int, Lane]

@export var pool: NotePool

## Spawn all the notes that should exist on this beat.
func update(beat: float) -> void:
	var old_begin: int = _begin
	var old_end: int = _end
	_update_view_relative_to_notes(notes, beat) # Updates _begin and _end.
	
	if _previous_beat <= beat:
		_set_note_visuals(old_end, _end)
		_remove_note_visuals(old_begin, _begin)
	else:
		_remove_note_visuals(_end, old_end)
		_set_note_visuals(_begin, old_begin)
	
	_previous_beat = beat
	notes_spawned.emit(beat)

# ======== IMPLEMENTATION ======== #
var _note_visuals: Dictionary[int, NoteVisual] # [Note ID, Note Visual]

var _last_lane_holds: Dictionary[int, HoldNote]

func _set_notes(p_notes: NoteArray) -> void:
	super._set_notes(p_notes)
	for note in _note_visuals.values():
		if note == null:
			continue
		pool.return_note(note)

# TODO Finish implementation.
# Spawn or delete nodes in the range.
func _set_note_visuals(index_begin: int, index_end: int) -> void:
	for note_id: int in range(index_begin, index_end):
		match notes.type_at(note_id):
			Note.TYPE.TAP:
				_set_visual_for_tap_at(note_id)
			Note.TYPE.HOLD_START:
				_set_visual_for_hold_start_at(note_id)
			Note.TYPE.HOLD_END:
				_set_visual_for_hold_end_at(note_id)

func _remove_note_visuals(index_begin: int, index_end: int) -> void:
	for note_id: int in range(index_begin, index_end):
		match notes.type_at(note_id):
			Note.TYPE.TAP:
				_remove_visual_for_tap_at(note_id)
			Note.TYPE.HOLD_START:
				_remove_visual_for_hold_start_at(note_id)
			Note.TYPE.HOLD_END:
				_remove_visual_for_hold_end_at(note_id)

func _set_visual_for_tap_at(note_id: int) -> void:
	var lane_id: int = notes.lane_at(note_id)
	var lane: Lane = lanes[lane_id]
	var note: TapNote = pool.get_tap()
	lane.add_child(note)
	_note_visuals[note_id] = note

func _set_visual_for_hold_start_at(note_id: int) -> void:
	var lane_id: int = notes.lane_at(note_id)
	var lane: Lane = lanes[lane_id]
	var note: HoldNote = pool.get_hold()
	lane.add_child(note)
	_note_visuals[note_id] = note
	_last_lane_holds[lane_id] = note

func _set_visual_for_hold_end_at(note_id: int) -> void:
	var lane_id: int = notes.lane_at(note_id)
	var lane: Lane = lanes[lane_id]
	var note: HoldNote = _last_lane_holds[lane_id]
	if note == null:
		note = pool.get_hold()
	lane.add_child(note)
	_note_visuals[note_id] = note
	_last_lane_holds[lane_id] = null

func _remove_visual_for_tap_at(note_id: int) -> void:
	pass

func _remove_visual_for_hold_start_at(note_id: int) -> void:
	pass

func _remove_visual_for_hold_end_at(note_id: int) -> void:
	pass
