class_name HItemList extends HBoxContainer

signal selected(item: Option, index, int)

@export var item_scene: PackedScene
@export var max_items: int = 4
@export var buffered_items: int = 1
@onready var buffer_size = max_items + (buffered_items * 2)

var items: Array = []
var create_item: Callable = _create_item
var bind_item: Callable = _bind_item
var ring_buffer: RingBuffer

func _ready() -> void:
    ring_buffer = RingBuffer.new(items.size(), buffer_size, buffer_size - 1)
    ring_buffer.rotated.connect(_on_rotated)

    for _i in range(buffer_size):
        add_child(create_item.call())

    _hide_buffered_items()

func _hide_buffered_items():
    for i in range(buffered_items):
        get_child(i).hide()

    var length = buffer_size - 1
    for i in range(length, length - buffered_items, -1):
        get_child(i).hide()

func _create_item() -> Node:
    return item_scene.instantiate()

func _bind_item(node: Node, item: Option):
    if node.has_method('bind'):
        node.call('bind', item)

func _on_rotated(_direction: int):
    _update_display()

func _get_item(index: int) -> Option:
    if index < 0 or index >= len(items):
        return Option.none
    return Option.from(items[index])

func _update_display():
    var iter = ring_buffer.iter()
    var indices = iter.collect()

    for i in range(buffer_size):
        var node = get_child(i)
        var item_index_from_ring_buffer = indices[i]
        var item_option = _get_item(item_index_from_ring_buffer)
        bind_item.call(node, item_option)

    var selected_item = _get_item(indices[buffered_items])
    selected.emit(selected_item)

func add_item(item: Variant):
    items.append(item)
    ring_buffer.source_size = items.size()
    _update_display()

func add_items(new_items: Array):
    items.append_array(new_items)
    ring_buffer.source_size = items.size()
    _update_display()

func move_right():
    ring_buffer.move_right()

func move_left():
    ring_buffer.move_left()
