
AIPlayers = { }
AIBarracks = { }
AIDerricks = { }
AIBaseLocation = { }
IdlingAIActors = { }
IdlingAISupportActors = { }
AIOnDefense = { }

-- It's good to start with 10 rifle man, one medic and 5 rocket soldiers
InitialUnitsToBuild = { "e1", "e1", "e1", "e1", "e1", "medi", "e1", "e1", "e1", "e1", "e1", "e3", "e3", "e3", "e3", "e3" }
UnitsToBuild = { "e1", "e1", "e1", "e1", "e1", "e3", "e3", "e3", "medi" }

ActivateAI = function(player, id)
	AIPlayers[id] = player

	Trigger.AfterDelay(0, function()
		local barracks = player.GetActorsByType("tent")
		if #barracks > 0 then
			AIBarracks[id] = barracks[1]
			AIBaseLocation[id] = barracks[1].Location + CVec.New(2, 1)
			IdlingAIActors[id] = { }
			IdlingAISupportActors[id] = { }
			InitialInfantryProduction(id, InitialUnitsToBuild)
			DefendActor(id, barracks[1])
			RepairBarracks(id)
			SellWalls(id)

			Trigger.AfterDelay(DateTime.Seconds(10), function() LookOutForCrates(id) end)
		end

		local derricks = player.GetActorsByType("oilb")
		if #derricks > 0 then
			AIDerricks[id] = derricks[1]
			DefendActor(id, derricks[1])
		end
	end)
end

InitialInfantryProduction = function(id, units)
	local productionComplete = AIPlayers[id].Build(units, function(actors)
		InfantryProduction(id)
	end)

	Trigger.OnProduction(AIBarracks[id], function(producer, produced)
		BuildComplete(id, produced)
	end)
end

InfantryProduction = function(id)
	local productionComplete = AIPlayers[id].Build({ Utils.Random(UnitsToBuild) }, function(actors)
		Trigger.AfterDelay(0, function() InfantryProduction(id) end)
	end)

	if not productionComplete then
		Trigger.AfterDelay(0, function() InfantryProduction(id) end)
	end
end

BuildComplete = function(id, actor)
	if actor.Type == "medi" then
		local number = #IdlingAISupportActors[id] + 1
		IdlingAISupportActors[id][number] = actor

		Trigger.OnKilled(actor, function()
			table.remove(IdlingAISupportActors[id], number)
		end)
	else
		local number = #IdlingAIActors[id] + 1
		IdlingAIActors[id][number] = actor

		Trigger.OnKilled(actor, function()
			table.remove(IdlingAIActors[id], number)
		end)
	end

	Trigger.AfterDelay(0, function() DefendActor(id, actor) end)
end

AttackGroupSize = 5
SetupAttackGroup = function(id)
	local units = { }

	for i = 0, AttackGroupSize, 1 do
		if (#IdlingAIActors[id] == 0) then
			return units
		end

		local number = Utils.RandomInteger(0, #IdlingAIActors[id]) + 1
		units[#units + 1] = IdlingAIActors[id][number]
		table.remove(IdlingAIActors[id], number)
	end

	return units
end

DefendActor = function(id, actorToDefend)
	if not actorToDefend or actorToDefend.IsDead or not actorToDefend.IsInWorld then
		return
	end

	Trigger.OnDamaged(actorToDefend, function(self, attacker)
		if AIOnDefense[id] or not attacker or attacker.IsDead then
			return
		end

		-- Don't try to kill something you can't kill
		if attacker.Type == "sniper.soviets" then
			return
		end

		AIOnDefense[id] = true
		local attackLoc = attacker.Location

		local defenders = SetupAttackGroup(id)
		if not defenders or #defenders == 0 then
			Trigger.AfterDelay(DateTime.Seconds(30), function() AIOnDefense[id] = false end)
			return
		end

		Utils.Do(defenders, function(unit)
			if unit.IsDead then
				return
			end

			unit.AttackMove(attackLoc)

			local home = AIBaseLocation[id]
			Trigger.OnIdle(unit, function()
				if unit.Location == home then
					IdlingAIActors[id][#IdlingAIActors[id] + 1] = unit
					Trigger.Clear(unit, "OnIdle")
					AIOnDefense[id] = false
				else
					unit.AttackMove(home)
				end
			end)
		end)
	end)
end

RepairBarracks = function(id)
	Trigger.OnDamaged(AIBarracks[id], function(self, attacker)
		self.StartBuildingRepairs(AIPlayers[id])
	end)
end

SellWalls = function(id)
	Media.DisplayMessage("Lonestar AI " .. id .. " sold its walls for better combat experience.")

	local walls = AIPlayers[id].GetActorsByType("brik")
	Utils.Do(walls, function(wall)
		wall.Sell()
	end)
end

LookOutForCrates = function(id)
	Trigger.OnEnteredProximityTrigger(AIBarracks[id].CenterPosition, WDist.New(12 * 1024), function(actor)
		if actor.Type ~= "fortcrate" or #IdlingAIActors[id] == 0 then
			return
		end

		local unit = Utils.Random(IdlingAIActors[id])
		local home = AIBaseLocation[id]
		local aim = actor.Location
		if unit.IsDead then
			return
		end

		unit.AttackMove(aim)
		Trigger.OnIdle(unit, function()
			if unit.Location == aim or not actor.IsInWorld then
				unit.AttackMove(home)
				Trigger.Clear(unit, "OnIdle")
			else
				unit.AttackMove(aim)
			end
		end)
	end)
end
