extends CharacterBody2D
class_name UFO

@export var movement_speed: float = 800.0
@export var radius: float = 150.0
var max_velocity: float = movement_speed
@onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D
@onready var plants: Node = $"../../Plants"
var target: Plant = null
var target2: Plant = null
var announce_self: bool = false
var dead = false
@export_range(1.0, 1000.0) var dps: float = 10.0
@export var max_hp = 100.0
var hp: float
var dead_timer: Timer = Timer.new()
@export var wheat_out: int = 3
var Wheat = preload("res://scene/entity/wheat.tscn")
@export var should_rotate: bool = true
@onready var ray = $Plx/Ray
@onready var ray2 = find_child("Ray2")
var attack_range = 1000.0
var second_player = find_child("AudioStreamPlayer2D2")
@onready var power_level: float = $"../../Waves".power_level
@onready var ROOT = get_tree().get_root().get_child(0)

func fuck():
    return false

func _ready():
    # Workaround bug body->get_space()
    call_deferred("actor_setup")
    navigation_agent.connect("velocity_computed", move)
    
    max_hp *= power_level
    dps *= power_level * pow(power_level, 0.7)
    
    $RerollTimer.connect("timeout", roll_movement_target_2)
    $DamageTimer.connect("timeout", damage_target)
    
    navigation_agent.set_path_desired_distance(40.0)
    navigation_agent.set_target_desired_distance(attack_range)
    navigation_agent.set_path_max_distance(200.0)
    navigation_agent.set_avoidance_enabled(true)
    if ROOT.disable_ai:
        navigation_agent.set_radius(0)
    else:
        navigation_agent.set_radius(radius)
    navigation_agent.set_neighbor_distance(movement_speed * 2)
    navigation_agent.set_max_speed(movement_speed)
    
    $AudioStreamPlayer2D.set_bus("Music" + str(randi_range(0, 3)))
    $AudioStreamPlayer2D.play($"../../HomeSound".get_playback_position())
    
    if second_player != null:
        second_player.set_bus("Music" + str(randi_range(0, 3)))
        second_player.play($"../../HomeSound".get_playback_position())
        
    hp = max_hp
    $Plx/HP.set_max(max_hp)
    $Plx/HP.set_value(max_hp)

func _process(delta):
    if dead:
        _process_dead(delta)
        return
    if target == null or target.dead or !is_instance_valid(target):
        if target2 != null:
            target = target2
            target2 = null
        else:
            target = roll_movement_target()
            hide_ray(ray)
    if navigation_agent.is_target_reached() and target != null:
        enable_ray(ray, target)
        if ray2 != null:
            if target2 == null or target2.dead:
                target2 = roll_aux_target()
            if target2 != null:
                enable_ray(ray2, target2)
            else:
                hide_ray(ray2)
        if $DamageTimer.is_stopped():
            $DamageTimer.start()
    else:
        hide_ray(ray)
        hide_ray(ray2)
        $DamageTimer.stop()

func _process_dead(delta: float):
    var time_left = dead_timer.get_time_left() * 3.0
    var scale = ease(time_left, 5)
    set_scale(Vector2(scale, scale))
    $AudioStreamPlayer2D.set_volume_db($AudioStreamPlayer2D.get_volume_db() - delta * 30.0)
    if second_player != null:
        second_player.set_volume_db(second_player.get_volume_db() - delta * 30.0)
    if time_left == 0.0:
        get_parent().remove_child(self)
        queue_free() 

func _physics_process(delta):
    if fuck():
        return
    if navigation_agent.is_target_reached():
        var new_speed = velocity.length() - delta * movement_speed * 2.0
        velocity = velocity.normalized() * new_speed
        move_and_slide()
    else:
        var current_agent_position: Vector2 = global_transform.origin
        var next_path_position: Vector2 = navigation_agent.get_next_location()
        var new_velocity: Vector2 = next_path_position - current_agent_position
        new_velocity = new_velocity.normalized()
        new_velocity = new_velocity * movement_speed
        navigation_agent.set_velocity(new_velocity)

func actor_setup():
    await get_tree().physics_frame
    target = roll_movement_target()
    
func roll_movement_target_2():
    target = roll_movement_target()

func roll_movement_target():
    var all_plants = plants.get_children()
    var count = all_plants.size()
    announce_self = true
    var res: UFO = null
    if count == 0:
        $RerollTimer.start()
    else:
        var i = 0
        while (res == null or res.dead or !is_instance_valid(res)) and i < 10:
            res = all_plants[randi_range(0, count - 1)]
            i += 1
        if i == 10:
            res = null
            $RerollTimer.start()
        else:
            navigation_agent.set_target_location(res.get_global_position())
    return res
    
func roll_aux_target():
    var all_plants = plants.get_children()
    for plant in all_plants:
        if plant != target and plant.get_global_position().distance_to(get_global_position()) <= attack_range:
            return plant
    return null

func damage_target():
    if target != null:
        target.deal_damage(dps / 20.0, self if announce_self else null)
    if target2 != null:
        target2.deal_damage(dps / 20.0, self if announce_self else null)

func move(velocity_: Vector2):
    velocity = velocity_
    move_and_slide()
    if should_rotate:
        var top = find_child("Top")
        top.set_rotation(lerp_angle(top.get_rotation(), velocity.angle(), 10.0 * get_physics_process_delta_time()))

func _on_area_2d_body_entered(body):
    if body.get_class() == "Bullet":
        deal_damage(body.damage)
        body.get_parent().remove_child(body)
        body.queue_free()
        
func deal_damage(damage):
    hp -= damage
    $Plx/HP.set_value(hp)
    if hp <= 0 and not dead:
        dead = true
        $Coin.play()
        set_collision_layer_value(1, false)
        set_collision_mask_value(1, false)
        $Plx/HP.hide()
        dead_timer.set_wait_time(0.333)
        dead_timer.set_one_shot(true)
        add_child(dead_timer)
        dead_timer.start()
        $DamageTimer.stop()
        hide_ray(ray)
        hide_ray(ray2)
        call_deferred("spawn_wheat")

func spawn_wheat():
    if ROOT.disable_wheat:
        $"../../Economy".add(ceil(wheat_out * sqrt(power_level)))
    else:
        for i in range(0, ceil(wheat_out * sqrt(power_level))):
            var wheat = Wheat.instantiate()
            wheat.rotate(randf_range(-PI, PI))
            wheat.set_position(get_global_position())
            $"../../Wheat".add_child(wheat)

func enable_ray(ray, target: Node2D):
    if ray != null:
        var diff = target.get_global_position() - get_global_position()
        var poly = ray.get_polygon()
        poly[1] = diff + Vector2(-80.0, target.body.texture.get_size().y / 2 + 30.0)
        poly[2] = diff + Vector2(80.0, target.body.texture.get_size().y / 2 + 30.0)
        ray.set_polygon(poly)
        ray.show()

func hide_ray(r):
    if r != null:
        r.hide()
        
    
