@tool
extends Node3D
class_name VendingMachine3d

const LINE_OBJECT_NUMBER = 5
const LINE_OBJECT_SEPARATION = Vector3.LEFT * 0.2
const FALLING_OBJECT_LINE_SHIFT = Vector3.FORWARD * 0.3

enum State {CHOOSE,PAY,FETCH,DONE, OFF}
enum ChooseState {NONE,FIRST,SECOND}

signal used

@export_tool_button("Update", "Callable") var update_action = update

@export_tool_button("Fall Object 1", "Callable") var fall_object_1_action = fall_object_1
@export_tool_button("Fall Object 1", "Callable") var fall_object_2_action = fall_object_2

@export var state : State = State.CHOOSE : set = set_state
@export var choose_state : ChooseState = ChooseState.NONE : set = set_choose_state
@export var artefact_1 : Artefact = null : set = set_artefact_1
@export var artefact_2 : Artefact = null : set = set_artefact_2
@export var price : VendingMachinePrice = null : set = set_price

# func _input(_e):
#     if Input.is_action_just_pressed("action"):
#         fall_object([
#             %Line1,
#             %Line2,
#             %Line3,        
#             %Line4
#         ].pick_random())

func _ready():
    update()

func update():
    set_artefact_1()
    set_artefact_2()
    set_state()
    set_price()
    set_choose_state()

func set_state(s := state):
    state = s
    %Select1Interactable.visible = s == State.CHOOSE or s == State.PAY
    %Select1Interactable.interactable = (s == State.CHOOSE or s == State.PAY) and artefact_1 != null

    %Select2Interactable.visible = s == State.CHOOSE or s == State.PAY
    %Select2Interactable.interactable = s == State.CHOOSE or s == State.PAY and artefact_2 != null

    %PayInteractable.visible = s == State.PAY
    %PayInteractable.interactable = s == State.PAY

    %FetchInteractable.visible = s == State.FETCH
    %FetchInteractable.interactable = s == State.FETCH

    %TopScreen.visible = s != State.OFF
    %InfoScreen.visible = s != State.OFF
    %PriceScreen.visible = s != State.OFF
    %Light.visible = s != State.OFF
    %SoundEffect.playing = s != State.OFF

    match state:
        State.CHOOSE:
            %InfoScreenLabel.text = "CHOOSE_AN_ITEM"
        State.PAY:
            if get_choosen_artefact():
                var choosen_artefact_name = get_choosen_artefact().get_artefact_name()
                %InfoScreenLabel.text = tr("PAY_THE_PRICE_FOR").format({
                    "item_name": tr(choosen_artefact_name),
                })
        State.FETCH:
            %InfoScreenLabel.text = "GET_YOUR_ITEM"
        State.DONE:
            %InfoScreenLabel.text = "THANK_YOU_FOR_YOUR_PURCHASE"

func set_artefact_1(a := artefact_1):
    if is_node_ready():
        if a:
            fill_lines(%Line1, a.get_3d_scene().instantiate())
            fill_lines(%Line2, a.get_3d_scene().instantiate())
        else: 
            clear_line(%Line1)
            clear_line(%Line2)
        %Select1Interactable.artefact = a
    artefact_1 = a

func set_artefact_2(a := artefact_2):
    if is_node_ready():
        if a:
            fill_lines(%Line3, a.get_3d_scene().instantiate())
            fill_lines(%Line4, a.get_3d_scene().instantiate())
        else: 
            clear_line(%Line3)
            clear_line(%Line4)
        %Select2Interactable.artefact = a
    artefact_2 = a

func set_price(p := price):
    if p and is_node_ready():
        %PriceScreenLabel.text = p.get_text()
        %PriceScreenIcon.texture = p.get_icon()
        if not Engine.is_editor_hint():
            %PriceScreenContentSprite.modulate = Color.WHITE if p.can_pay(GameInfo.game_data.player_data) else Color.RED
            %PayIcon.modulate = Color.WHITE if p.can_pay(GameInfo.game_data.player_data) else Color.RED
    price = p

func set_choose_state(cs := choose_state):
    if is_node_ready():
        %SelectTop.visible = cs == ChooseState.FIRST
        %SelectBottom.visible = cs == ChooseState.SECOND
    choose_state = cs

func fall_object_1():
    fall_object([
        %Line1,
        %Line2
    ].pick_random())

func fall_object_2():
    fall_object([
        %Line3,
        %Line4
    ].pick_random())

func fall_object(from_line : Node3D):
    if len(from_line.get_children()):
        var falling_object = create_falling_object()

        var object = from_line.get_children().pick_random() as Node3D

        var falling_model = object.duplicate()
        falling_model.position = Vector3.ZERO
        falling_object.add_child(falling_model)
        falling_object.freeze = false
        object.queue_free()

        %FallingObjects.add_child(falling_object)
        falling_object.global_position = object.global_position + FALLING_OBJECT_LINE_SHIFT.rotated(Vector3.UP, rotation.y)

func clear_falling_objects():
    for c in %FallingObjects.get_children():
        c.queue_free()

func create_falling_object() -> RigidBody3D:
    var falling_object = RigidBody3D.new()
    var falling_collider = CollisionShape3D.new()
    var falling_shape = SphereShape3D.new()
    falling_shape.radius = 0.08
    falling_collider.shape = falling_shape
    falling_object.add_child(falling_collider)
    falling_object.gravity_scale = 0.2

    return falling_object

func fill_lines(line : Node3D, object : Node3D):
    clear_line(line)

    for i in range(LINE_OBJECT_NUMBER):
        var new_object = object.duplicate()
        line.add_child(new_object)
        new_object.position = i * LINE_OBJECT_SEPARATION
    
func clear_line(line : Node3D):
    for c in line.get_children():
        c.queue_free()

func get_choosen_artefact() -> Artefact:
    if choose_state == ChooseState.FIRST:
        return artefact_1
    elif choose_state == ChooseState.SECOND:
        return artefact_2
    return null

func _on_select_1_interactable_clicked():
    AudioManager.play_sfx("Screen_interaction")
    choose_state = ChooseState.FIRST
    state = State.PAY


func _on_select_2_interactable_clicked():
    AudioManager.play_sfx("Screen_interaction")
    choose_state = ChooseState.SECOND
    state = State.PAY


func _on_pay_interactable_clicked():
    if price.can_pay(GameInfo.game_data.player_data):
        AudioManager.play_sfx("Drop")
        price.pay(GameInfo.game_data.player_data)
        if choose_state == ChooseState.FIRST:
            fall_object_1()
        else:
            fall_object_2()
        
        state = State.FETCH
        get_tree().create_timer(0.5).timeout.connect(
            func ():
                AudioManager.play_sfx("VendingMachineDrop")
        )


func _on_fetch_interactable_clicked():
    AudioManager.play_sfx("PickUp")
    clear_falling_objects()
    if GameInfo.game_data and GameInfo.game_data.current_region_data and GameInfo.game_data.current_run:
        GameInfo.game_data.current_run.add_artefacts(get_choosen_artefact().duplicate())

    state = State.DONE

    used.emit()

    get_tree().create_timer(1.).timeout.connect(
        func (): %ArtefactAnnounce.announce_artefact = get_choosen_artefact()
    );

    get_tree().create_timer(3.).timeout.connect(
        func ():
            state = State.OFF
            AudioManager.play_sfx("VendingMachineOff")
    )
