local orb = module.internal('orb')
local gpred = module.internal('gpred')
local mymenu

mymenu = menu("orb_menu", "Kite-Helper 0.1.2 | Klee and EftU")
mymenu:slider("power", "Space Power", 10, 0, 10, 1)
mymenu:boolean("debug", "Debug (for dev)", false)
mymenu:keybind("toggle", "Toggle Script", "T", "G") -- Toggle key
mymenu:boolean("health_toggle", "Disable on low health", true)
mymenu:menu("health_settings", "Health Settings")
mymenu:boolean("combo_only_champions", "Only champions (need a fix)", true)
for i = 0, objManager.enemies_n - 1 do
    local enemy = objManager.enemies[i]
    if enemy then
        mymenu.health_settings:slider("health_" .. enemy.charName, "Disable if " .. enemy.charName .. " health < %", 50, 0, 100, 1)
    end
end
for i = 0, objManager.enemies_n - 1 do
    local enemy = objManager.enemies[i]
    if enemy then
        mymenu:boolean("use_on_" .. enemy.charName, "Use on " .. enemy.charName, true)
    end
end
mymenu:boolean("draw_circles", "Drawings(for dev)", true)
mymenu:boolean("follow_after_attack", "Follow Enemy After Attack (NOT WORK)", true)
mymenu:menu("drawing_settings", "Drawing Settings")
mymenu.drawing_settings:boolean("enable_drawings", "Enable Movement Drawings", true)
mymenu:menu("draw_aa_settings", "Auto-Attack Radius Settings")
mymenu.draw_aa_settings:boolean("enable_my_aa", "Enable My AA Radius", true)
mymenu.draw_aa_settings:boolean("enable_enemy_aa", "Enable Enemy AA Radius", true)
for i = 0, objManager.enemies_n - 1 do
    local enemy = objManager.enemies[i]
    if enemy then
        mymenu.draw_aa_settings:boolean("enable_aa_" .. enemy.charName, "Enable AA for " .. enemy.charName, true)
    end
end

local function debug_print(text)
    if mymenu.debug:get() then
        chat.print(text)
    end
end

local function is_valid(target)
    return target and target.valid and not target.isDead and target.isVisible and target.isTargetable
end

local function extend_vec(from, to, range)
    if not from or not to then
        return nil -- Default value
    end
    return from + ((to - from):norm() * range)
end

local function in_aa_range(_src, _target, extra)
    if not _src or not _target then return false end

    return _src.pos:dist(_target.pos) <=
        _src.attackRange + _src.boundingRadius + _target.boundingRadius + (extra or 0)
end

local function get_predicted_enemy_position(enemy, time)
    local current_pos = enemy.pos
    local path = enemy.path
    if path and path.isDashing then
        return path.dashEndPos
    elseif path and path.hasMovePath then
        local move_speed = enemy.moveSpeed
        return current_pos + path.point[2]:norm() * move_speed * time
    else
        return current_pos
    end
end

local function get_kiting_distance(enemy)
    local enemy_attack_range = enemy.attackRange + enemy.boundingRadius
    local my_attack_range = player.attackRange + player.boundingRadius
    local my_attack_speed = player:attackDelay()
    local speed_difference = player.moveSpeed - enemy.moveSpeed

    local base_distance = 100 -- Base distance for kiting
    local distance = base_distance + (enemy_attack_range / 2) - (my_attack_speed * 10) + (speed_difference * 5) + (my_attack_range / 2)
    return math.max(50, math.min(distance, 500)) -- limit distance between 50 to 500
end

local function avoid_behavior(close_enemy)
    local enemy_direction = (player.pos - close_enemy.pos):norm()
    local perpendicular_dir = vec3(-enemy_direction.z, 0, enemy_direction.x)
    local avoid_position = player.pos + perpendicular_dir * 100 -- Adjust vector length to change distance
    return avoid_position
end

local function correct_position_if_obstructed(original_pos, direction, range)
    local corrected_pos = original_pos
    if navmesh.isWall(corrected_pos) then
        corrected_pos = player:getPassablePos(corrected_pos)
    end
    -- Minion avoidance
    for i = 0, objManager.minions.size[TEAM_ENEMY] - 1 do
        local minion = objManager.minions[TEAM_ENEMY][i]
        if minion and minion.isVisible and minion.isTargetable and minion.pos:dist(corrected_pos) < range then
            corrected_pos = extend_vec(corrected_pos, minion.pos, -minion.boundingRadius * 1.5)
            break
        end
    end
    return corrected_pos
end

local function on_tick()
    if not mymenu.toggle:get() then return end

    if orb.menu.combat.key:get() then
        local target = orb.combat.target
        if target and not target.isHero and mymenu.combo_only_champions:get() then
            debug_print("Target is not a champion, script will not execute.")
            return
        end

        if target and not in_aa_range(player, target, 25) then
            debug_print("Target is out of range, script will not execute.")
            return
        end
    else
        return
    end

    local closest_enemy = nil
    local min_distance = math.huge

    for i = 0, objManager.enemies_n - 1 do
        local enemy = objManager.enemies[i]
        local distance = player.pos:dist(enemy.pos)
        if is_valid(enemy) and distance < min_distance then
            min_distance = distance
            closest_enemy = enemy
        end
    end

    if not is_valid(closest_enemy) then
        debug_print("No valid enemy found.")
        return
    end

    if not in_aa_range(player, closest_enemy, 50) then
        debug_print("Closest enemy is out of attack range.")
        return
    end

    local time_until_next_aa = orb.core.time_to_next_attack()
    if time_until_next_aa == 0 then
        debug_print("Can move and attack.")
        return
    end

    local attack_windup = player:attackDelay() - player:attackCastDelay(64)
    if time_until_next_aa >= attack_windup then
        debug_print("Can move, but can't attack.")
        return
    end

    local space_power = mymenu.power:get() / 10
    if time_until_next_aa < attack_windup - attack_windup * space_power then
        debug_print("Stop space (menu)")
        return
    end

    local predicted_enemy_pos = get_predicted_enemy_position(closest_enemy, 0.5)
    local kiting_distance = get_kiting_distance(closest_enemy)
    local space_pos = extend_vec(player.pos, predicted_enemy_pos, -kiting_distance)

    if navmesh.isWall(space_pos) then
        local avoid_pos = avoid_behavior(closest_enemy)
        space_pos = correct_position_if_obstructed(avoid_pos, closest_enemy.pos, 100)
    end

    orb.core.set_pause_move(0.02)
    player:move(space_pos)
end

local function on_draw()
    if mymenu.drawing_settings.enable_drawings:get() then
        local space_pos = player.pos -- Default to player's current position
        graphics.draw_circle(space_pos, 50, 1, 0xff00ff00, 36)
    end
end

cb.add(cb.draw, on_draw)
cb.add(cb.tick, on_tick)