local X             = {}
local bot           = GetBot()

local J             = require( GetScriptDirectory()..'/FunLib/jmz_func' )
local Minion        = dofile( GetScriptDirectory()..'/FunLib/aba_minion' )
local sTalentList   = J.Skill.GetTalentList( bot )
local sAbilityList  = J.Skill.GetAbilityList( bot )
local sRole   = J.Item.GetRoleItemsBuyList( bot )

local tTalentTreeList = {
						{--pos2
                            ['t25'] = {0, 10},
                            ['t20'] = {10, 0},
                            ['t15'] = {0, 10},
                            ['t10'] = {0, 10},
                        },
                        {--pos3
                            ['t25'] = {0, 10},
                            ['t20'] = {10, 0},
                            ['t15'] = {0, 10},
                            ['t10'] = {10, 0},
                        }
}

local tAllAbilityBuildList = {
						{2,3,2,3,2,6,2,3,3,1,6,1,1,1,6},--pos2
                        {2,3,2,1,2,6,2,3,3,3,6,1,1,1,6},--pos3
}

local nAbilityBuildList = tAllAbilityBuildList[2]
local nTalentBuildList = J.Skill.GetTalentBuild(tTalentTreeList[2])

if sRole == "pos_2"
then
    nAbilityBuildList   = tAllAbilityBuildList[1]
    nTalentBuildList    = J.Skill.GetTalentBuild(tTalentTreeList[1])
elseif sRole == "pos_3"
then
    nAbilityBuildList   = tAllAbilityBuildList[2]
    nTalentBuildList    = J.Skill.GetTalentBuild(tTalentTreeList[2])
end

local sRoleItemsBuyList = {}

sRoleItemsBuyList['pos_2'] = {
    "item_tango",
    "item_double_branches",

    "item_double_wraith_band",
    "item_power_treads",
    "item_soul_ring",
    "item_magic_wand",
	"item_orchid",
    "item_bloodthorn",--
    "item_black_king_bar",--
    "item_sheepstick",--
    "item_aghanims_shard",
    "item_nullifier",--
    "item_skadi",--
    "item_travel_boots_2",--
    "item_moon_shard",
    "item_ultimate_scepter",
    "item_ultimate_scepter_2",
}

sRoleItemsBuyList['pos_3'] = {
    "item_tango",
    "item_double_branches",

    "item_double_wraith_band",
    "item_power_treads",
    "item_soul_ring",
    "item_magic_wand",
	"item_orchid",
    "item_bloodthorn",--
    "item_black_king_bar",--
    "item_assault",--
    "item_aghanims_shard",
    "item_sheepstick",--
    "item_skadi",--
    "item_travel_boots_2",--
    "item_moon_shard",
    "item_ultimate_scepter",
    "item_ultimate_scepter_2",
}

sRoleItemsBuyList['pos_1'] = sRoleItemsBuyList['pos_3']

sRoleItemsBuyList['pos_4'] = sRoleItemsBuyList['pos_3']

sRoleItemsBuyList['pos_5'] = sRoleItemsBuyList['pos_3']

X['sBuyList'] = sRoleItemsBuyList[sRole]

X['sSellList'] = {
	"item_power_treads",
	"item_quelling_blade",

}

if J.Role.IsPvNMode() or J.Role.IsAllShadow() then X['sBuyList'], X['sSellList'] = { 'PvN_antimage' }, {} end

nAbilityBuildList, nTalentBuildList, X['sBuyList'], X['sSellList'] = J.SetUserHeroInit( nAbilityBuildList, nTalentBuildList, X['sBuyList'], X['sSellList'] )

X['sSkillList'] = J.Skill.GetSkillList( sAbilityList, nAbilityBuildList, sTalentList, nTalentBuildList )

X['bDeafaultAbility'] = false
X['bDeafaultItem'] = false

function X.MinionThink(hMinionUnit)
	Minion.MinionThink(hMinionUnit)
end

local InsatiableHunger  = bot:GetAbilityByName('broodmother_insatiable_hunger')
local SpinWeb           = bot:GetAbilityByName('broodmother_spin_web')
-- local SilkenBola        = bot:GetAbilityByName('broodmother_silken_bola')
-- local SpinnersSnare     = bot:GetAbilityByName('broodmother_sticky_snare')
local SpawnSpiderlings  = bot:GetAbilityByName('broodmother_spawn_spiderlings')

local InsatiableHungerDesire
local SpinWebDesire, SpinWebLocation
-- local SilkenBolaDesire, SilkenBolaTarget
-- local SpinnersSnareDesire, SpinnersSnareLocation -- No Unit.
local SpawnSpiderlingsDesire, SpirderlingsTarget
local WebGapTime = 1
local LastWebTime = 0

function X.SkillsComplement()
	if J.CanNotUseAbility(bot) then return end

    SpawnSpiderlingsDesire, SpirderlingsTarget = X.ConsiderSpawnSpiderlings()
    if SpawnSpiderlingsDesire > 0
    then
        bot:Action_UseAbilityOnEntity(SpawnSpiderlings, SpirderlingsTarget)
        return
    end

    SpinWebDesire, SpinWebLocation = X.ConsiderSpinWeb()
    if SpinWebDesire > 0
    then
        if DotaTime() - LastWebTime > WebGapTime then
            bot:Action_UseAbilityOnLocation(SpinWeb, SpinWebLocation)
            LastWebTime = DotaTime()
        end
        return
    end

    -- SilkenBolaDesire, SilkenBolaTarget = X.ConsiderSilkenBola()
    -- if SilkenBolaDesire > 0
    -- then
    --     bot:Action_UseAbilityOnEntity(SilkenBola, SilkenBolaTarget)
    --     return
    -- end

    InsatiableHungerDesire = X.ConsiderInsatiableHunger()
    if InsatiableHungerDesire > 0
    then
        bot:Action_UseAbility(InsatiableHunger)
        return
    end
end

function X.ConsiderInsatiableHunger()
    if not InsatiableHunger:IsFullyCastable()
    then
        return BOT_ACTION_DESIRE_NONE
    end

    local nAttackRange = bot:GetAttackRange()
    local botTarget = J.GetProperTarget(bot)

    if J.IsInTeamFight(bot, 1200)
	then
        local nInRangeEnemy = J.GetEnemiesNearLoc(bot:GetLocation(), 1200)

        if nInRangeEnemy ~= nil and #nInRangeEnemy >= 2
        and J.GetHP(bot) < 0.75
        and J.IsAttacking(bot)
        then
			return BOT_ACTION_DESIRE_HIGH
        end
	end

    if J.IsGoingOnSomeone(bot)
	then
		if J.IsValidTarget(botTarget)
        and J.IsInRange(bot, botTarget, nAttackRange + 150)
        and J.IsAttacking(bot)
        and not J.IsSuspiciousIllusion(botTarget)
        and not J.IsDisabled(botTarget)
        and not botTarget:HasModifier('modifier_abaddon_borrowed_time')
        and not botTarget:HasModifier('modifier_dazzle_shallow_grave')
        and not botTarget:HasModifier('modifier_faceless_void_chronosphere_freeze')
        and not botTarget:HasModifier('modifier_necrolyte_reapers_scythe')
        and not botTarget:HasModifier('modifier_oracle_false_promise_timer')
        and not botTarget:HasModifier('modifier_templar_assassin_refraction_absorb')
		then
            local nInRangeAlly = J.GetNearbyHeroes(botTarget, 1200, true, BOT_MODE_NONE)
            local nInRangeEnemy = J.GetNearbyHeroes(botTarget, 1200, false, BOT_MODE_NONE)

            if nInRangeAlly ~= nil and nInRangeEnemy ~= nil
            and #nInRangeAlly >= #nInRangeEnemy
            then
                return BOT_ACTION_DESIRE_HIGH
            end
		end
	end

    if J.IsFarming(bot)
    then
        local nCreeps = bot:GetNearbyCreeps(700, true)

        if nCreeps ~= nil and #nCreeps > 0
        and J.GetHP(bot) < 0.4
        and J.IsAttacking(bot)
        then
            return BOT_ACTION_DESIRE_HIGH
        end
    end

    if J.IsDoingRoshan(bot)
	then
		if J.IsRoshan(botTarget)
        and J.IsInRange(bot, botTarget, 500)
        and J.IsAttacking(bot)
		then
			return BOT_ACTION_DESIRE_HIGH
		end
	end

    if J.IsDoingTormentor(bot)
    then
        if J.IsTormentor(botTarget)
        and J.IsInRange(bot, botTarget, 500)
        and J.IsAttacking(bot)
        then
            return BOT_ACTION_DESIRE_HIGH
        end
    end

    return BOT_ACTION_DESIRE_NONE
end

function X.ConsiderSpinWeb()
    if not SpinWeb:IsFullyCastable()
    then
        return BOT_ACTION_DESIRE_NONE, 0
    end

	local nCastRange = J.GetProperCastRange(false, bot, SpinWeb:GetCastRange())
    local nRadius = SpinWeb:GetSpecialValueInt('radius')
    local nEnemyLaneCreeps = bot:GetNearbyLaneCreeps(nCastRange, true)
    local nEnemyTowers = bot:GetNearbyTowers(nCastRange, true)
    local botTarget = J.GetProperTarget(bot)

    if J.IsStuck(bot)
    and not DoesLocationHaveWeb(bot:GetLocation(), nRadius)
	then
		return BOT_ACTION_DESIRE_HIGH, bot:GetLocation()
	end

    if J.IsInTeamFight(bot, 1200)
	then
        local nLocationAoE = bot:FindAoELocation(true, true, bot:GetLocation(), nCastRange, nRadius, 0, 0)
        local nInRangeEnemy = J.GetEnemiesNearLoc(nLocationAoE.targetloc, nRadius / 1.7)

        if nInRangeEnemy ~= nil and #nInRangeEnemy >= 2
        and not DoesLocationHaveWeb(nLocationAoE.targetloc, nRadius)
        and not J.IsLocationInChrono(nLocationAoE.targetloc)
        and not J.IsLocationInBlackHole(nLocationAoE.targetloc)
        then
			return BOT_ACTION_DESIRE_HIGH, nLocationAoE.targetloc
        end
	end

    if J.IsGoingOnSomeone(bot)
	then
		if J.IsValidTarget(botTarget)
        and J.IsInRange(bot, botTarget, nCastRange)
        and not J.IsSuspiciousIllusion(botTarget)
        and not J.IsDisabled(botTarget)
        and not botTarget:HasModifier('modifier_abaddon_borrowed_time')
        and not botTarget:HasModifier('modifier_dazzle_shallow_grave')
        and not botTarget:HasModifier('modifier_necrolyte_reapers_scythe')
        and not botTarget:HasModifier('modifier_oracle_false_promise_timer')
        and not DoesLocationHaveWeb(botTarget:GetLocation(), nRadius)
        and not J.IsLocationInChrono(botTarget:GetLocation())
        and not J.IsLocationInBlackHole(botTarget:GetLocation())
		then
            local nInRangeAlly = J.GetNearbyHeroes(botTarget, 1200, true, BOT_MODE_NONE)
            local nInRangeEnemy = J.GetNearbyHeroes(botTarget, 1200, false, BOT_MODE_NONE)

            if nInRangeAlly ~= nil and nInRangeEnemy ~= nil
            and #nInRangeAlly >= #nInRangeEnemy
            then
                return BOT_ACTION_DESIRE_HIGH, botTarget:GetLocation()
            end
		end
	end

    if J.IsRetreating(bot)
	then
        local nInRangeAlly = J.GetNearbyHeroes(bot,1200, false, BOT_MODE_NONE)
        local nInRangeEnemy = J.GetNearbyHeroes(bot,1200, true, BOT_MODE_NONE)

        if nInRangeAlly ~= nil and nInRangeEnemy ~= nil
        and J.IsValidHero(nInRangeEnemy[1])
        and J.IsInRange(bot, nInRangeEnemy[1], 600)
        and J.IsChasingTarget(nInRangeEnemy[1], bot)
        and not J.IsSuspiciousIllusion(nInRangeEnemy[1])
        and not J.IsDisabled(nInRangeEnemy[1])
        and not DoesLocationHaveWeb(bot:GetLocation(), nRadius)
        then
            local nTargetInRangeAlly = J.GetNearbyHeroes(nInRangeEnemy[1], 1200, false, BOT_MODE_NONE)

            if nTargetInRangeAlly ~= nil
            and ((#nTargetInRangeAlly > #nInRangeAlly)
                or (bot:WasRecentlyDamagedByAnyHero(1.5)))
            then
		        return BOT_ACTION_DESIRE_HIGH, bot:GetLocation()
            end
        end
    end

    if J.IsPushing(bot)
	then
		if nEnemyLaneCreeps ~= nil and #nEnemyLaneCreeps >= 4
        and not DoesLocationHaveWeb(J.GetCenterOfUnits(nEnemyLaneCreeps), nRadius)
        then
			return BOT_ACTION_DESIRE_HIGH, J.GetCenterOfUnits(nEnemyLaneCreeps)
		end

		if nEnemyTowers ~= nil and #nEnemyTowers >= 1
        and J.CanBeAttacked(nEnemyTowers[1])
        and not DoesLocationHaveWeb(nEnemyTowers[1]:GetLocation(), nRadius)
		then
			return BOT_ACTION_DESIRE_HIGH, nEnemyTowers[1]:GetLocation()
		end
	end

    if J.IsLaning(bot)
    then
		if nEnemyLaneCreeps ~= nil and #nEnemyLaneCreeps >= 4
        and not DoesLocationHaveWeb(J.GetCenterOfUnits(nEnemyLaneCreeps), nRadius)
        then
			return BOT_MODE_DESIRE_HIGH, J.GetCenterOfUnits(nEnemyLaneCreeps)
		end
	end

    if J.IsDoingRoshan(bot)
	then
		if J.IsRoshan(botTarget)
        and J.IsInRange(bot, botTarget, 500)
        and J.IsAttacking(bot)
        and not DoesLocationHaveWeb(botTarget:GetLocation(), nRadius)
		then
			return BOT_ACTION_DESIRE_HIGH, botTarget:GetLocation()
		end
	end

    if J.IsDoingTormentor(bot)
    then
        if J.IsTormentor(botTarget)
        and J.IsInRange(bot, botTarget, 500)
        and J.IsAttacking(bot)
        and not DoesLocationHaveWeb(botTarget:GetLocation(), nRadius)
        then
            return BOT_ACTION_DESIRE_HIGH, botTarget:GetLocation()
        end
    end

    return BOT_ACTION_DESIRE_NONE, 0
end

-- function X.ConsiderSilkenBola()
-- 	if not SilkenBola:IsFullyCastable()
--     then
-- 		return BOT_ACTION_DESIRE_NONE, nil
-- 	end

-- 	local nCastRange = SilkenBola:GetCastRange()
--     local nDamage = SilkenBola:GetSpecialValueInt('impact_damage')
--     local botTarget = J.GetProperTarget(bot)

--     local nEnemyHeroes = J.GetNearbyHeroes(bot,nCastRange, true, BOT_MODE_NONE)
--     for _, enemyHero in pairs(nEnemyHeroes)
--     do
--         if J.IsValidHero(enemyHero)
--         and J.CanCastOnNonMagicImmune(enemyHero)
--         and J.CanKillTarget(enemyHero, nDamage, DAMAGE_TYPE_MAGICAL)
--         and not J.IsSuspiciousIllusion(enemyHero)
--         and not enemyHero:HasModifier('modifier_abaddon_borrowed_time')
--         and not enemyHero:HasModifier('modifier_dazzle_shallow_grave')
--         and not enemyHero:HasModifier('modifier_necrolyte_reapers_scythe')
--         and not enemyHero:HasModifier('modifier_oracle_false_promise_timer')
--         and not enemyHero:HasModifier('modifier_templar_assassin_refraction_absorb')
--         then
--             return BOT_ACTION_DESIRE_HIGH, enemyHero
--         end
--     end

--     if J.IsGoingOnSomeone(bot)
-- 	then
-- 		if J.IsValidTarget(botTarget)
--         and J.IsInRange(bot, botTarget, nCastRange)
--         and not J.IsSuspiciousIllusion(botTarget)
--         and not botTarget:HasModifier('modifier_abaddon_borrowed_time')
--         and not botTarget:HasModifier('modifier_dazzle_shallow_grave')
--         and not botTarget:HasModifier('modifier_necrolyte_reapers_scythe')
--         and not botTarget:HasModifier('modifier_oracle_false_promise_timer')
-- 		then
--             local nInRangeAlly = J.GetNearbyHeroes(botTarget, 1200, true, BOT_MODE_NONE)
--             local nInRangeEnemy = J.GetNearbyHeroes(botTarget, 1200, false, BOT_MODE_NONE)

--             if nInRangeAlly ~= nil and nInRangeEnemy ~= nil
--             and #nInRangeAlly >= #nInRangeEnemy
--             then
--                 return BOT_ACTION_DESIRE_HIGH, botTarget
--             end
-- 		end
-- 	end

--     if J.IsRetreating(bot)
-- 	then
--         local nInRangeAlly = J.GetNearbyHeroes(bot,1200, false, BOT_MODE_NONE)
--         local nInRangeEnemy = J.GetNearbyHeroes(bot,1200, true, BOT_MODE_NONE)

--         if nInRangeAlly ~= nil and nInRangeEnemy ~= nil
--         and J.IsValidHero(nInRangeEnemy[1])
--         and J.IsInRange(bot, nInRangeEnemy[1], nCastRange)
--         and J.IsChasingTarget(nInRangeEnemy[1], bot)
--         and not J.IsSuspiciousIllusion(nInRangeEnemy[1])
--         and not nInRangeEnemy[1]:HasModifier('modifier_necrolyte_reapers_scythe')
--         then
--             local nTargetInRangeAlly = J.GetNearbyHeroes(nInRangeEnemy[1], 1200, false, BOT_MODE_NONE)

--             if nTargetInRangeAlly ~= nil
--             and ((#nTargetInRangeAlly > #nInRangeAlly)
--                 or (bot:WasRecentlyDamagedByAnyHero(1.5)))
--             then
-- 		        return BOT_ACTION_DESIRE_HIGH, nInRangeEnemy[1]
--             end
--         end
--     end

--     if J.IsLaning(bot)
-- 	then
-- 		local nEnemyLaneCreeps = bot:GetNearbyLaneCreeps(nCastRange, true)

-- 		for _, creep in pairs(nEnemyLaneCreeps)
-- 		do
-- 			if J.IsValid(creep)
-- 			and (J.IsKeyWordUnit('ranged', creep) or J.IsKeyWordUnit('siege', creep) or J.IsKeyWordUnit('flagbearer', creep))
-- 			and creep:GetHealth() <= nDamage
-- 			then
-- 				local nCreepInRangeHero = creep:GetNearbyHeroes(500, false, BOT_MODE_NONE)

-- 				if nCreepInRangeHero ~= nil and #nCreepInRangeHero >= 1
--                 and J.GetMP(bot) > 0.49
-- 				then
-- 					return BOT_ACTION_DESIRE_HIGH, creep
-- 				end
-- 			end
-- 		end
-- 	end

--     if J.IsDoingRoshan(bot)
-- 	then
-- 		if J.IsRoshan(botTarget)
--         and J.IsInRange(bot, botTarget, 500)
--         and J.IsAttacking(bot)
-- 		then
-- 			return BOT_ACTION_DESIRE_HIGH, botTarget
-- 		end
-- 	end

--     if J.IsDoingTormentor(bot)
--     then
--         if J.IsTormentor(botTarget)
--         and J.IsInRange(bot, botTarget, 500)
--         and J.IsAttacking(bot)
--         then
--             return BOT_ACTION_DESIRE_HIGH, botTarget
--         end
--     end

--     local nAllyHeroes = J.GetNearbyHeroes(bot,nCastRange, false, BOT_MODE_NONE)
--     for _, allyHero in pairs(nAllyHeroes)
--     do
--         local nAllyInRangeEnemy = J.GetNearbyHeroes(allyHero, 1200, true, BOT_MODE_NONE)

--         if J.IsValidHero(allyHero)
--         and J.IsRetreating(allyHero)
--         and J.GetMP(bot) > 0.45
--         and allyHero:WasRecentlyDamagedByAnyHero(1.5)
--         and not allyHero:IsIllusion()
--         then
--             if nAllyInRangeEnemy ~= nil and #nAllyInRangeEnemy >= 1
--             and J.IsValidHero(nAllyInRangeEnemy[1])
--             and J.CanCastOnNonMagicImmune(nAllyInRangeEnemy[1])
--             and J.CanCastOnTargetAdvanced(nAllyInRangeEnemy[1])
--             and J.IsInRange(bot, nAllyInRangeEnemy[1], nCastRange)
--             and J.IsChasingTarget(nAllyInRangeEnemy[1], allyHero)
--             and not J.IsDisabled(nAllyInRangeEnemy[1])
--             and not J.IsTaunted(nAllyInRangeEnemy[1])
--             and not J.IsSuspiciousIllusion(nAllyInRangeEnemy[1])
--             and not nAllyInRangeEnemy[1]:HasModifier('modifier_legion_commander_duel')
--             and not nAllyInRangeEnemy[1]:HasModifier('modifier_enigma_black_hole_pull')
--             and not nAllyInRangeEnemy[1]:HasModifier('modifier_faceless_void_chronosphere_freeze')
--             and not nAllyInRangeEnemy[1]:HasModifier('modifier_necrolyte_reapers_scythe')
--             then
--                 return BOT_ACTION_DESIRE_HIGH, nAllyInRangeEnemy[1]
--             end
--         end
--     end

-- 	return BOT_ACTION_DESIRE_NONE, nil
-- end

function X.ConsiderSpawnSpiderlings()
	if not SpawnSpiderlings:IsFullyCastable()
    then
		return BOT_ACTION_DESIRE_NONE, 0
	end

	local nCastRange = J.GetProperCastRange(false, bot, SpawnSpiderlings:GetCastRange())
	local nDamage = SpawnSpiderlings:GetSpecialValueInt('damage')

    local nEnemyHeroes = J.GetNearbyHeroes(bot,nCastRange, true, BOT_MODE_NONE)
    for _, enemyHero in pairs(nEnemyHeroes)
    do
        if J.IsValidHero(enemyHero)
        and J.CanCastOnNonMagicImmune(enemyHero)
        and J.CanKillTarget(enemyHero, nDamage, DAMAGE_TYPE_MAGICAL)
        and not J.IsSuspiciousIllusion(enemyHero)
        and not enemyHero:HasModifier('modifier_abaddon_borrowed_time')
        and not enemyHero:HasModifier('modifier_dazzle_shallow_grave')
        and not enemyHero:HasModifier('modifier_necrolyte_reapers_scythe')
        and not enemyHero:HasModifier('modifier_oracle_false_promise_timer')
        and not enemyHero:HasModifier('modifier_templar_assassin_refraction_absorb')
        then
            return BOT_ACTION_DESIRE_HIGH, enemyHero
        end
    end

    local nCreeps = bot:GetNearbyLaneCreeps(nCastRange, true)
    for _, creep in pairs(nCreeps)
    do
        if J.IsValid(creep)
        and J.CanBeAttacked(creep)
        and J.CanKillTarget(creep, nDamage, DAMAGE_TYPE_MAGICAL)
        and not J.IsRetreating(bot)
        then
            return BOT_ACTION_DESIRE_HIGH, creep
        end
    end

	return BOT_ACTION_DESIRE_NONE, 0
end

-- Helper Funcs
function DoesLocationHaveWeb(loc, nRadius)
	for _, u in pairs (GetUnitList(UNIT_LIST_ALLIES))
	do
		if J.IsValid(u)
        and u:GetUnitName() == 'npc_dota_broodmother_web'
        and GetUnitToLocationDistance(u, loc) < nRadius
		then
			return true
		end
	end

	return false
end

return X