local Utility = require("Utility")
local AutoStash = require("AutoStash")

local AutoUseItems = {}

AutoUseItems.optionSoulRing = Menu.AddOption({"Item Specific"}, "Soul Ring", "Auto use soul ring before casting spells or items")
AutoUseItems.optionTomeOfKnowledge = Menu.AddOption({"Item Specific"}, "Tome of Knowledge", "Auto purchase tome of knowledge once available")
AutoUseItems.optionMidas = Menu.AddOption({"Item Specific"}, "Hand of Midas", "Auto use midas on high XP creeps once available")
AutoUseItems.optionDeward = Menu.AddOption({"Item Specific"}, "Deward", "Auto use quelling blade, iron talen, battle fury, or tango to deward")
AutoUseItems.optionIronTalon = Menu.AddOption({"Item Specific"}, "Iron Talon", "Auto use iron talen to remove creep's HP")
AutoUseItems.optionHeal = Menu.AddOption({"Item Specific"}, "Heal", "Auto use magic wand(stick) or faerie fire if HP is low")
AutoUseItems.optionSheepstick = Menu.AddOption({"Item Specific"}, "Sheepstick", "Auto use sheepstick on enemy hero once available")
AutoUseItems.optionDiffusal = Menu.AddOption({"Item Specific"}, "Diffusal Blade", "Auto use diffusal blade once enemy is within range")
AutoUseItems.optionHeavens = Menu.AddOption({"Item Specific"}, "Heavens", "Auto use heavens on selected enemy hero (e.g., PA, AM) once available")
AutoUseItems.optionOrchid = Menu.AddOption({"Item Specific"}, "Orchid & Bloodthorn", "Auto use orchid or bloodthorn on enemy hero once available")
AutoUseItems.optionAtos = Menu.AddOption({"Item Specific"}, "Rod of Atos", "Auto use atos on enemy hero once available")
AutoUseItems.optionShivas = Menu.AddOption({"Item Specific"}, "Shiva's Guard", "Auto use Shivas once enemy is within range")
AutoUseItems.optionAbyssal = Menu.AddOption({"Item Specific"}, "Abyssal Blade", "Auto use abyssal blade on enemy hero once available")
AutoUseItems.optionDagon = Menu.AddOption({"Item Specific"}, "Dagon", "Auto use dagon to KS or break linkens")
AutoUseItems.optionVeil = Menu.AddOption({"Item Specific"}, "Veil of Discord", "Auto use veil once available")
AutoUseItems.optionLotus = Menu.AddOption({"Item Specific"}, "Lotus Orb", "(For tinker) auto use lotus orb on self or allies once available")
AutoUseItems.optionCrest = Menu.AddOption({"Item Specific"}, "Medallion & Crest", "Auto use medallion & crest to save ally")
AutoUseItems.optionGlimmerCape = Menu.AddOption({"Item Specific"}, "Glimmer Cape", "Auto use Glimmer Cape when channeling spells or ally in danger")
AutoUseItems.optionGhost = Menu.AddOption({"Item Specific"}, "Ghost Scepter", "Auto use ghost scepter to avoid damage from physical cores")
AutoUseItems.optionSatanic = Menu.AddOption({"Item Specific"}, "Satanic", "Auto use Satanic when (i) legion or axe is around; or (ii) hp is low and my hero is attacking.")

function AutoUseItems.OnUpdate()
    local myHero = Heroes.GetLocal()
    if not myHero then return end

    -- ========================
    -- Items dont't break channeling spell (Shivas, Glimmer Cape, etc)
    -- ========================
    if Menu.IsEnabled(AutoUseItems.optionGlimmerCape) and (Utility.IsSuitableToUseItem(myHero) or Utility.IsChannellingAbility(myHero)) then
        AutoUseItems.item_glimmer_cape(myHero)
    end

    if not Utility.IsSuitableToUseItem(myHero) then return end
    -- ========================
    -- Defensive items
    -- ========================
    if Menu.IsEnabled(AutoUseItems.optionTomeOfKnowledge) then
        AutoUseItems.item_tome_of_knowledge(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionMidas) then
        AutoUseItems.item_hand_of_midas(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionDeward) then
        AutoUseItems.deward(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionIronTalon) then
        AutoUseItems.item_iron_talon(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionHeal) then
        AutoUseItems.heal(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionLotus) then
        AutoUseItems.item_lotus_orb(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionCrest) then
        AutoUseItems.item_solar_crest(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionGhost) then
        AutoUseItems.item_ghost(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionSatanic) then
        AutoUseItems.item_satanic(myHero)
    end

    -- ========================
    -- Aggressive items
    -- ========================
    if Menu.IsEnabled(AutoUseItems.optionSheepstick) and NPC.IsVisible(myHero) then
        AutoUseItems.item_sheepstick(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionDiffusal) and NPC.IsVisible(myHero) then
        AutoUseItems.item_diffusal_blade(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionHeavens) and NPC.IsVisible(myHero) then
        AutoUseItems.item_heavens_halberd(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionOrchid) and NPC.IsVisible(myHero) then
        AutoUseItems.item_orchid(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionAtos) and NPC.IsVisible(myHero) then
        AutoUseItems.item_rod_of_atos(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionShivas) and NPC.IsVisible(myHero) then
        AutoUseItems.item_shivas_guard(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionAbyssal) and NPC.IsVisible(myHero) then
        AutoUseItems.item_abyssal_blade(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionDagon) and NPC.IsVisible(myHero) then
        AutoUseItems.item_dagon(myHero)
    end

    if Menu.IsEnabled(AutoUseItems.optionVeil) and NPC.IsVisible(myHero) then
        AutoUseItems.item_veil_of_discord(myHero)
    end
end

-- auto use soul ring before casting spells or items
function AutoUseItems.OnPrepareUnitOrders(orders)
    if not Menu.IsEnabled(AutoUseItems.optionSoulRing) then return true end
    if not orders or not orders.ability then return true end

    if not Entity.IsAbility(orders.ability) then return true end
    if Ability.GetManaCost(orders.ability) <= 0 then return true end

    local myHero = Heroes.GetLocal()
    if not myHero or NPC.IsStunned(myHero) then return true end

    local soul_ring = NPC.GetItem(myHero, "item_soul_ring", true)
    if not soul_ring or not Ability.IsCastable(soul_ring, 0) then return true end

    local HpThreshold = 200
    if Entity.GetHealth(myHero) <= HpThreshold then return true end

    -- If in base, stash items before using soul ring.
    -- It has to team with stash2inventory() action in AutoStash.lua
    if NPC.HasModifier(myHero, "modifier_fountain_aura_buff") then
        AutoStash.inventory2stash(myHero)
    end

    Ability.CastNoTarget(soul_ring)
    return true
end

-- auto purchase tome of knowledge once available
function AutoUseItems.item_tome_of_knowledge(myHero)
end

-- auto use midas on high XP creeps once available
function AutoUseItems.item_hand_of_midas(myHero)
    local item = NPC.GetItem(myHero, "item_hand_of_midas", true)
    if not item or not Ability.IsCastable(item, 0) then return end

    local range = Utility.GetCastRange(myHero, item) -- 600
    local XP_threshold = 88
    local creeps = NPC.GetUnitsInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)
    for i, npc in ipairs(creeps) do
        local XP = NPC.GetBountyXP(npc)
        if NPC.IsCreep(npc) and not Utility.IsAncientCreep(npc) and XP >= XP_threshold then
            Ability.CastTarget(item, npc)
            return
        end
    end
end

-- Auto use quelling blade, iron talen, or battle fury to deward
function AutoUseItems.deward(myHero)
    local item1 = NPC.GetItem(myHero, "item_quelling_blade", true)
    local item2 = NPC.GetItem(myHero, "item_iron_talon", true)
    local item3 = NPC.GetItem(myHero, "item_bfury", true)
    local item4 = NPC.GetItem(myHero, "item_tango", true)
    local item5 = NPC.GetItem(myHero, "item_tango_single", true)

    local item = nil
    if item1 and Ability.IsCastable(item1, 0) then item = item1 end
    if item2 and Ability.IsCastable(item2, 0) then item = item2 end
    if item3 and Ability.IsCastable(item3, 0) then item = item3 end
    if item4 and Ability.IsCastable(item4, 0) then item = item4 end
    if item5 and Ability.IsCastable(item5, 0) then item = item5 end
    if not item then return end

    local range = 450
    local wards = NPC.GetUnitsInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)
    for i, npc in ipairs(wards) do
        if NPC.GetUnitName(npc) == "npc_dota_observer_wards" or NPC.GetUnitName(npc) == "npc_dota_sentry_wards" then
            Ability.CastTarget(item, npc)
            return
        end
    end
end

-- Auto use iron talon to remove creep's HP
function AutoUseItems.item_iron_talon(myHero)
    local item = NPC.GetItem(myHero, "item_iron_talon", true)
    if not item or not Ability.IsCastable(item, 0) then return end

    local HpThreshold = 550
    local range = Utility.GetCastRange(myHero, item) -- 350
    local creeps = NPC.GetUnitsInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)

    for i, npc in ipairs(creeps) do
        if npc and NPC.IsCreep(npc) and Entity.GetHealth(npc) >= HpThreshold and not Utility.IsAncientCreep(npc) then
            Ability.CastTarget(item, npc)
            return
        end
    end
end

-- Auto use magic wand(stick) or faerie fire if HP is low
function AutoUseItems.heal(myHero)
    local item1 = NPC.GetItem(myHero, "item_magic_stick", true)
    local item2 = NPC.GetItem(myHero, "item_magic_wand", true)
    local item3 = NPC.GetItem(myHero, "item_faerie_fire", true)

    local item = nil
    if item1 and Ability.IsCastable(item1, 0) and Item.GetCurrentCharges(item1)>0 then item = item1 end
    if item2 and Ability.IsCastable(item2, 0) and Item.GetCurrentCharges(item2)>0 then item = item2 end
    if item3 and Ability.IsCastable(item3, 0) then item = item3 end
    if not item then return end

    local HpThreshold = 200
    if Entity.GetHealth(myHero) <= HpThreshold then
        Ability.CastNoTarget(item)
    end
end

-- Auto use sheepstick on enemy hero once available
-- Doesn't use on enemy who is lotus orb protected or AM with aghs.
function AutoUseItems.item_sheepstick(myHero)
    local item = NPC.GetItem(myHero, "item_sheepstick", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local range = Utility.GetCastRange(myHero, item) -- 800
    local enemyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)

    local minDistance = 99999
    local target = nil
    for i, enemy in ipairs(enemyAround) do
        if not NPC.IsIllusion(enemy) and not Utility.IsDisabled(enemy)
            and Utility.CanCastSpellOn(enemy) and not Utility.IsLinkensProtected(enemy)
            and not Utility.IsLotusProtected(enemy) then
            local dis = (Entity.GetAbsOrigin(myHero) - Entity.GetAbsOrigin(enemy)):Length()
            if dis < minDistance then
                minDistance = dis
                target = enemy
            end
        end
    end

    -- cast sheepstick on nearest enemy in range
    if target then Ability.CastTarget(item, target) end
end

-- Auto use sheepstick on enemy hero once available
-- Doesn't use on enemy who is lotus orb protected or AM with aghs.
function AutoUseItems.item_diffusal_blade(myHero)
    local item = NPC.GetItem(myHero, "item_diffusal_blade", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local range = Utility.GetCastRange(myHero, item) -- 600
    local enemyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)

    local minDistance = 99999
    local target = nil
    for i, enemy in ipairs(enemyAround) do
        if not NPC.IsIllusion(enemy) and not Utility.IsDisabled(enemy)
            and Utility.CanCastSpellOn(enemy) and not Utility.IsLinkensProtected(enemy)
            and not Utility.IsLotusProtected(enemy) then
            local dis = (Entity.GetAbsOrigin(myHero) - Entity.GetAbsOrigin(enemy)):Length()
            if dis < minDistance then
                minDistance = dis
                target = enemy
            end
        end
    end

    -- cast sheepstick on nearest enemy in range
    if target then Ability.CastTarget(item, target) end
end

-- Auto use sheepstick on enemy hero once available
-- Doesn't use on enemy who is lotus orb protected or AM with aghs.
function AutoUseItems.item_heavens_halberd(myHero)
    local item = NPC.GetItem(myHero, "item_heavens_halberd", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local range = Utility.GetCastRange(myHero, item) -- 600
    local enemyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)

    local minDistance = 99999
    local target = nil
    for i, enemy in ipairs(enemyAround) do
        if not NPC.IsIllusion(enemy) and not Utility.IsDisabled(enemy) and Utility.CanCastSpellOn(enemy)
        	and (Utility.PhysicalCoreHeroes[NPC.GetUnitName(enemy)] or NPC.IsLinkensProtected(enemy)) then
            local dis = (Entity.GetAbsOrigin(myHero) - Entity.GetAbsOrigin(enemy)):Length()
            if dis < minDistance then
                minDistance = dis
                target = enemy
            end
        end
    end

    -- cast item_heavens_halberd on nearest key enemy in range
    if target then Ability.CastTarget(item, target) end
end

-- Auto use orchid or bloodthorn on enemy hero once available
-- Doesn't use on enemy who is lotus orb protected or AM with aghs.
function AutoUseItems.item_orchid(myHero)
    local item1 = NPC.GetItem(myHero, "item_orchid", true)
    local item2 = NPC.GetItem(myHero, "item_bloodthorn", true)

    local item = nil
    if item1 and Ability.IsCastable(item1, NPC.GetMana(myHero)) then item = item1 end
    if item2 and Ability.IsCastable(item2, NPC.GetMana(myHero)) then item = item2 end
    if not item then return end

    local range = Utility.GetCastRange(myHero, item)
    local enemyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)

    local minDistance = 99999
    local target = nil
    for i, enemy in ipairs(enemyAround) do
        if not NPC.IsIllusion(enemy) and not Utility.IsDisabled(enemy)
            and Utility.CanCastSpellOn(enemy) and not NPC.IsSilenced(enemy) and not Utility.IsLotusProtected(enemy) then
            local dis = (Entity.GetAbsOrigin(myHero) - Entity.GetAbsOrigin(enemy)):Length()
            if dis < minDistance then
                minDistance = dis
                target = enemy
            end
        end
    end

    -- cast orchid/bloodthorn on nearest enemy in range
    if target then Ability.CastTarget(item, target) end
end

-- Auto use rod of atos on enemy hero once available
-- Doesn't use on enemy who is lotus orb protected or AM with aghs.
function AutoUseItems.item_rod_of_atos(myHero)
    local item = NPC.GetItem(myHero, "item_rod_of_atos", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local range = Utility.GetCastRange(myHero, item)
    local enemyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)

    local minDistance = 99999
    local target = nil
    for i, enemy in ipairs(enemyAround) do
        if not NPC.IsIllusion(enemy) and not Utility.IsDisabled(enemy)
            and Utility.CanCastSpellOn(enemy) and not Utility.IsLotusProtected(enemy)
            and not NPC.HasState(enemy, Enum.ModifierState.MODIFIER_STATE_ROOTED) then

            local dis = (Entity.GetAbsOrigin(myHero) - Entity.GetAbsOrigin(enemy)):Length()
            if dis < minDistance then
                minDistance = dis
                target = enemy
            end
        end
    end

    -- cast rod of atos on nearest enemy in range
    if target then Ability.CastTarget(item, target) end
end

-- Auto use Shiva's Guard once enemy is within range
function AutoUseItems.item_shivas_guard(myHero)
    local item = NPC.GetItem(myHero, "item_shivas_guard", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local radius = 900
    local enemyAround = NPC.GetHeroesInRadius(myHero, radius, Enum.TeamType.TEAM_ENEMY)

    for i, enemy in ipairs(enemyAround) do
        if not NPC.IsIllusion(enemy) and not Utility.IsDisabled(enemy) and Utility.CanCastSpellOn(enemy)
            and not NPC.HasState(enemy, Enum.ModifierState.MODIFIER_STATE_ROOTED) then
            Ability.CastNoTarget(item)
            return
        end
    end
end

-- Auto use abyssal blade on enemy hero once available
-- Doesn't use on enemy who is lotus orb protected or AM with aghs.
function AutoUseItems.item_abyssal_blade(myHero)
    local item = NPC.GetItem(myHero, "item_abyssal_blade", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local range = Utility.GetCastRange(myHero, item)
    local enemyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)

    local minDistance = 99999
    local target = nil
    for i, enemy in ipairs(enemyAround) do
        if not NPC.IsIllusion(enemy) and not NPC.IsStunned(enemy)
        and not Utility.IsLotusProtected(enemy) and not Utility.IsLinkensProtected(enemy) then
            local dis = (Entity.GetAbsOrigin(myHero) - Entity.GetAbsOrigin(enemy)):Length()
            if dis < minDistance then
                minDistance = dis
                target = enemy
            end
        end
    end

    -- cast rod of atos on nearest enemy in range
    if target then Ability.CastTarget(item, target) end
end

function AutoUseItems.item_dagon(myHero)
    local level, item
    local item1 = NPC.GetItem(myHero, "item_dagon", true)
    local item2 = NPC.GetItem(myHero, "item_dagon_2", true)
    local item3 = NPC.GetItem(myHero, "item_dagon_3", true)
    local item4 = NPC.GetItem(myHero, "item_dagon_4", true)
    local item5 = NPC.GetItem(myHero, "item_dagon_5", true)

    if item1 and Ability.IsCastable(item1, NPC.GetMana(myHero)) then item = item1; level = 1 end
    if item2 and Ability.IsCastable(item2, NPC.GetMana(myHero)) then item = item2; level = 2 end
    if item3 and Ability.IsCastable(item3, NPC.GetMana(myHero)) then item = item3; level = 3 end
    if item4 and Ability.IsCastable(item4, NPC.GetMana(myHero)) then item = item4; level = 4 end
    if item5 and Ability.IsCastable(item5, NPC.GetMana(myHero)) then item = item5; level = 5 end

    if not item then return end

    local range = Utility.GetCastRange(myHero, item) -- 600 + 50 * (level - 1)
    local magic_damage = 400 + 100 * (level - 1)

    local enemyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)
    for i, enemy in ipairs(enemyAround) do
        if enemy and not NPC.IsIllusion(enemy) and Utility.CanCastSpellOn(enemy) and Utility.IsSafeToCast(myHero, enemy, magic_damage) then

            local enemyHp = Entity.GetHealth(enemy)
            local true_damage = magic_damage * NPC.GetMagicalArmorDamageMultiplier(enemy)
            if enemyHp < true_damage or Utility.IsLinkensProtected(enemy) then
                Ability.CastTarget(item, enemy)
            end
        end
    end
end

function AutoUseItems.item_veil_of_discord(myHero)
    local item = NPC.GetItem(myHero, "item_veil_of_discord", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local range = Utility.GetCastRange(myHero, item) -- 1000
    local enemyHeroes = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_ENEMY)
    if not enemyHeroes or #enemyHeroes <= 0 then return end

    local radius = 600
    local pos = Utility.BestPosition(enemyHeroes, radius)
    if pos then Ability.CastPosition(item, pos) end
end

-- Auto cast lotus orb to save ally
-- For tinker, auto use lotus orb on self or allies once available
function AutoUseItems.item_lotus_orb(myHero)
    local item = NPC.GetItem(myHero, "item_lotus_orb", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    -- cast on self first if needed
    if Utility.NeedToBeSaved(myHero) then Ability.CastTarget(item, myHero); return end

    local range = Utility.GetCastRange(myHero, item) -- 900
    local allyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_FRIEND)
    if not allyAround or #allyAround <= 0 then return end

    -- save ally who get stunned, silenced, rooted, disarmed, low Hp, etc
    for i, ally in ipairs(allyAround) do
        if Utility.NeedToBeSaved(ally) and Utility.CanCastSpellOn(ally) then
            Ability.CastTarget(item, ally)
            return
        end
    end

    -- for tinker
    if NPC.GetUnitName(myHero) ~= "npc_dota_hero_tinker" then return end

    if not NPC.HasModifier(myHero, "modifier_item_lotus_orb_active") and Utility.CanCastSpellOn(myHero) then
        Ability.CastTarget(item, myHero)
        return
    end

    -- cast lotus orb once available
    for i, ally in ipairs(allyAround) do
        if Entity.IsAlive(ally) and not NPC.IsIllusion(ally) and Utility.CanCastSpellOn(ally)
            and not NPC.HasModifier(ally, "modifier_item_lotus_orb_active") then

            Ability.CastTarget(item, ally)
            return
        end
    end
end

-- Auto cast solar crest/medallion of courage to save ally
function AutoUseItems.item_solar_crest(myHero)
	local item
    local item1 = NPC.GetItem(myHero, "item_solar_crest", true)
    local item2 = NPC.GetItem(myHero, "item_medallion_of_courage", true)

    if item1 then item = item1 end
    if item2 then item = item2 end

    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    local range = Utility.GetCastRange(myHero, item) -- 1000
    local allyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_FRIEND)
    if not allyAround or #allyAround <= 0 then return end

    for i, ally in ipairs(allyAround) do
        if Utility.NeedToBeSaved(ally) and Utility.CanCastSpellOn(ally) then
            Ability.CastTarget(item, ally)
            return
        end
    end
end

-- Auto use ghost scepter to avoid damage from physical cores
function AutoUseItems.item_ghost(myHero)
    local item1 = NPC.GetItem(myHero, "item_ghost", true)
    local item2 = NPC.GetItem(myHero, "item_ethereal_blade", true)

    if (not item1 or not Ability.IsCastable(item1, NPC.GetMana(myHero)))
    and (not item2 or not Ability.IsCastable(item2, NPC.GetMana(myHero)))
    then return end

    for i = 1, Heroes.Count() do
        local enemy = Heroes.Get(i)
        if enemy and not NPC.IsIllusion(enemy) and not Entity.IsSameTeam(myHero, enemy)
        and not Utility.IsDisabled(enemy) and Utility.PhysicalCoreHeroes[NPC.GetUnitName(enemy)]
        and NPC.IsEntityInRange(myHero, enemy, NPC.GetAttackRange(enemy)) and not NPC.IsRanged(enemy) then

            if item1 and Ability.IsCastable(item1, NPC.GetMana(myHero)) then
                Ability.CastNoTarget(item1)
                return
            end
            
            if item2 and Ability.IsCastable(item2, NPC.GetMana(myHero)) then
                Ability.CastTarget(item2, myHero)
                return
            end
        end
    end
end

-- Auto use Satanic when (i) legion or axe is around; or (ii) hp is low and my hero is attacking.
function AutoUseItems.item_satanic(myHero)
    local item = NPC.GetItem(myHero, "item_satanic", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    -- when hp is low and myHero is attacking
    if Entity.GetHealth(myHero) <= 0.5 * Entity.GetMaxHealth(myHero) and NPC.IsAttacking(myHero) then
        Ability.CastNoTarget(item)
        return
    end

    -- when legion or axe is around
    for i = 1, Heroes.Count() do
        local enemy = Heroes.Get(i)
        if enemy and not NPC.IsIllusion(enemy) and not Entity.IsSameTeam(myHero, enemy)
        and not Utility.IsDisabled(enemy) and Utility.IsAxeOrLegion[NPC.GetUnitName(enemy)]
        and NPC.IsEntityInRange(myHero, enemy, 300) then

            Ability.CastNoTarget(item)
            return
        end
    end
end

-- Auto cast Glimmer Cape to ally or yourself when channeling spell or need to be saved.
function AutoUseItems.item_glimmer_cape(myHero)
    local item = NPC.GetItem(myHero, "item_glimmer_cape", true)
    if not item or not Ability.IsCastable(item, NPC.GetMana(myHero)) then return end

    if Utility.CanCastSpellOn(myHero) and (Utility.NeedToBeSaved(myHero) or Utility.IsChannellingAbility(myHero)) then
        Ability.CastTarget(item, myHero)
    end

    local range = Utility.GetCastRange(myHero, item) -- 1050
    local allyAround = NPC.GetHeroesInRadius(myHero, range, Enum.TeamType.TEAM_FRIEND)
    if not allyAround or #allyAround <= 0 then return end

    for i, ally in ipairs(allyAround) do
        if Utility.CanCastSpellOn(ally) and (Utility.NeedToBeSaved(ally) or Utility.IsChannellingAbility(ally)) then
            Ability.CastTarget(item, ally)
            return
        end
    end
end

return AutoUseItems
