--[[
   Copyright (c) The OpenRA Developers and Contributors
   This file is part of OpenRA, which is free software. It is made
   available to you under the terms of the GNU General Public License
   as published by the Free Software Foundation, either version 3 of
   the License, or (at your option) any later version. For more
   information, see COPYING.
]]

HarkonnenBase = { HarkonnenConstructionYard, HarkonnenWindTrap1, HarkonnenWindTrap2, HarkonnenWindTrap3, HarkonnenWindTrap4, HarkonnenWindTrap5, HarkonnenWindTrap6, HarkonnenWindTrap7, HarkonnenWindTrap8, HarkonnenSilo1, HarkonnenSilo2, HarkonnenSilo3, HarkonnenSilo4, HarkonnenGunTurret1, HarkonnenGunTurret2, HarkonnenGunTurret3, HarkonnenGunTurret4, HarkonnenGunTurret5, HarkonnenGunTurret6, HarkonnenGunTurret7, HarkonnenHeavyFactory, HarkonnenRefinery, HarkonnenOutpost, HarkonnenLightFactory }
SmugglerBase = { SmugglerWindTrap1, SmugglerWindTrap2 }

HarkonnenReinforcements =
{
	easy =
	{
		{ "combat_tank_h", "trooper", "trooper", "trooper", "trooper" },
		{ "trooper", "trooper", "trooper", "trooper", "trooper" },
		{ "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" }
	},

	normal =
	{
		{ "combat_tank_h", "trooper", "trooper", "trooper", "trooper" },
		{ "trooper", "trooper", "trooper", "trooper", "trooper" },
		{ "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "trike", "combat_tank_h", "light_inf", "trooper", "trooper", "quad" },
		{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" }
	},

	hard =
	{
		{ "combat_tank_h", "trooper", "trooper", "trooper", "trooper" },
		{ "trooper", "trooper", "trooper", "trooper", "trooper" },
		{ "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" },
		{ "combat_tank_h", "trike", "combat_tank_h", "light_inf", "trooper", "trooper", "quad" },
		{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" },
		{ "combat_tank_h", "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" },
		{ "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h" }
	}
}

HarkonnenInfantryReinforcements =
{
	normal =
	{
		{ "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" }
	},

	hard =
	{
		{ "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper" },
		{ "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" }
	}
}
InfantryPath = { HarkonnenEntry3.Location }

HarkonnenAttackDelay =
{
	easy = DateTime.Minutes(3),
	normal = DateTime.Minutes(2) + DateTime.Seconds(20),
	hard = DateTime.Minutes(1)
}

HarkonnenAttackWaves =
{
	easy = 5,
	normal = 7,
	hard = 9
}

MercenaryReinforcements =
{
	easy =
	{
		{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" },
		{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" },
		{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }
	},

	normal =
	{
		{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" },
		{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" },
		{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" },
		{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" },
		{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike" },
		{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }
	},

	hard =
	{
		{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" },
		{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" },
		{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" },
		{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike" },
		{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" },
		{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" },
		{ "combat_tank_o", "combat_tank_o", "quad", "quad", "trike", "trike", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" },
		{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike", "quad", "quad" },
		{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "trike", "trike", "quad", "quad", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }
	}
}

MercenaryAttackDelay =
{
	easy = DateTime.Minutes(2) + DateTime.Seconds(40),
	normal = DateTime.Minutes(1) + DateTime.Seconds(50),
	hard = DateTime.Minutes(1) + DateTime.Seconds(10)
}

MercenaryAttackWaves =
{
	easy = 3,
	normal = 6,
	hard = 9
}

MercenarySpawn = { HarkonnenRally4.Location + CVec.New(2, -2) }

-- Ordos tanks because those were intended for the Smugglers not the Atreides
ContrabandReinforcements = { "mcv", "quad", "quad", "combat_tank_o", "combat_tank_o", "combat_tank_o" }
SmugglerReinforcements = { "quad", "quad", "trike", "trike" }
InitialHarkonnenReinforcements = { "trooper", "trooper", "quad", "quad", "trike", "trike", "trike", "light_inf" }

HarkonnenPaths =
{
	{ HarkonnenEntry1.Location, HarkonnenRally1.Location },
	{ HarkonnenEntry1.Location, HarkonnenRally3.Location },
	{ HarkonnenEntry1.Location, HarkonnenRally2.Location },
	{ HarkonnenEntry1.Location, HarkonnenRally4.Location },
	{ HarkonnenEntry2.Location }
}

AtreidesReinforcements = { "trike", "combat_tank_a" }
AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location }

ContrabandTimes =
{
	easy = DateTime.Minutes(10),
	normal = DateTime.Minutes(5),
	hard = DateTime.Minutes(2) + DateTime.Seconds(30)
}

Wave = 0
SendHarkonnen = function()
	Trigger.AfterDelay(HarkonnenAttackDelay[Difficulty], function()
		if Atreides.IsObjectiveCompleted(KillHarkonnen) then
			return
		end

		Wave = Wave + 1

		if InfantryReinforcements and Wave % 4 == 0 then
			local inf = Reinforcements.Reinforce(Harkonnen, HarkonnenInfantryReinforcements[Difficulty][Wave/4], InfantryPath)
			Utils.Do(inf, function(unit)
				unit.AttackMove(HarkonnenAttackLocation)
				IdleHunt(unit)
			end)
		end

		local entryPath = Utils.Random(HarkonnenPaths)
		local units = Reinforcements.ReinforceWithTransport(Harkonnen, "carryall.reinforce", HarkonnenReinforcements[Difficulty][Wave], entryPath, { entryPath[1] })[2]
		Utils.Do(units, function(unit)
			unit.AttackMove(HarkonnenAttackLocation)
			IdleHunt(unit)
		end)

		if Wave < HarkonnenAttackWaves[Difficulty] then
			SendHarkonnen()
			return
		end

		Trigger.AfterDelay(DateTime.Seconds(3), function() LastHarkonnenArrived = true end)
	end)
end

MercWave = 0
SendMercenaries = function()
	Trigger.AfterDelay(MercenaryAttackDelay[Difficulty], function()
		MercWave = MercWave + 1

		Media.DisplayMessage(UserInterface.GetFluentMessage("incoming-mercenary-force"), Mentat)

		local units = Reinforcements.Reinforce(Mercenary, MercenaryReinforcements[Difficulty][MercWave], MercenarySpawn)
		Utils.Do(units, function(unit)
			unit.AttackMove(MercenaryAttackLocation1)
			unit.AttackMove(MercenaryAttackLocation2)
			IdleHunt(unit)
		end)

		if MercWave < MercenaryAttackWaves[Difficulty] then
			SendMercenaries()
			return
		end

		Trigger.AfterDelay(DateTime.Seconds(3), function() LastMercenariesArrived = true end)
	end)
end

SendContraband = function(owner)
	ContrabandArrived = true
	UserInterface.SetMissionText(UserInterface.GetFluentMessage("contraband-has-arrived"), Atreides.Color)

	local units = SmugglerReinforcements
	if owner == Atreides then
		units = ContrabandReinforcements
	end

	Reinforcements.ReinforceWithTransport(owner, "frigate", units, { ContrabandEntry.Location, Starport.Location + CVec.New(1, 1) }, { ContrabandExit.Location })

	Trigger.AfterDelay(DateTime.Seconds(3), function()
		if owner == Atreides then
			Atreides.MarkCompletedObjective(CaptureStarport)
			Media.DisplayMessage(UserInterface.GetFluentMessage("contraband-confiscated"), Mentat)
		else
			Atreides.MarkFailedObjective(CaptureStarport)
			Media.DisplayMessage(UserInterface.GetFluentMessage("contraband-not-confiscated"), Mentat)
		end
	end)

	Trigger.AfterDelay(DateTime.Seconds(5), function()
		UserInterface.SetMissionText("")
	end)
end

SmugglersAttack = function()
	Utils.Do(SmugglerBase, function(building)
		if not building.IsDead and building.Owner == Smuggler then
			building.Sell()
		end
	end)

	Trigger.AfterDelay(DateTime.Seconds(1), function()
		Utils.Do(Smuggler.GetGroundAttackers(), function(unit)
			IdleHunt(unit)
		end)
	end)
end

AttackNotifier = 0
Tick = function()
	if Atreides.HasNoRequiredUnits() then
		Harkonnen.MarkCompletedObjective(KillAtreides)
	end

	if LastHarkonnenArrived and not Atreides.IsObjectiveCompleted(KillHarkonnen) and Harkonnen.HasNoRequiredUnits() then
		Media.DisplayMessage(UserInterface.GetFluentMessage("harkonnen-annihilated"), Mentat)
		Atreides.MarkCompletedObjective(KillHarkonnen)
	end

	if LastMercenariesArrived and not Atreides.IsObjectiveCompleted(KillSmuggler) and Smuggler.HasNoRequiredUnits() and Mercenary.HasNoRequiredUnits() then
		Media.DisplayMessage(UserInterface.GetFluentMessage("smugglers-annihilated"), Mentat)
		Atreides.MarkCompletedObjective(KillSmuggler)
	end

	if LastHarvesterEaten[Harkonnen] and DateTime.GameTime % DateTime.Seconds(10) == 0 then
		local units = Harkonnen.GetActorsByType("harvester")

		if #units > 0 then
			LastHarvesterEaten[Harkonnen] = false
			ProtectHarvester(units[1], Harkonnen, AttackGroupSize[Difficulty])
		end
	end

	AttackNotifier = AttackNotifier - 1

	if TimerTicks and not ContrabandArrived then
		TimerTicks = TimerTicks - 1
		if (TimerTicks % DateTime.Seconds(1)) == 0 then
			local contrabandArrivesIn = UserInterface.GetFluentMessage("contraband-arrives-in", { ["time"] = Utils.FormatTime(TimerTicks)})
			UserInterface.SetMissionText(contrabandArrivesIn, Atreides.Color)
		end

		if TimerTicks <= 0 then
			SendContraband(Smuggler)
		end
	end
end

WorldLoaded = function()
	Harkonnen = Player.GetPlayer("Harkonnen")
	Smuggler = Player.GetPlayer("Smugglers")
	Mercenary = Player.GetPlayer("Mercenaries")
	Atreides = Player.GetPlayer("Atreides")

	InfantryReinforcements = Difficulty ~= "easy"

	InitObjectives(Atreides)
	KillAtreides = AddPrimaryObjective(Harkonnen, "")
	CaptureBarracks = AddPrimaryObjective(Atreides, "capture-barracks-sietch-tabr")
	KillHarkonnen = AddSecondaryObjective(Atreides, "annihilate-harkonnen-units-reinforcements")
	CaptureStarport = AddSecondaryObjective(Atreides, "capture-smuggler-starport-confiscate-contraband")

	Camera.Position = ARefinery.CenterPosition
	HarkonnenAttackLocation = AtreidesRally.Location
	MercenaryAttackLocation1 = Starport.Location + CVec.New(-16, 0)
	MercenaryAttackLocation2 = Starport.Location

	Trigger.AfterDelay(DateTime.Seconds(2), function()
		TimerTicks = ContrabandTimes[Difficulty]
		local time = Utils.FormatTime(TimerTicks)
		local contrabandApproaching = UserInterface.GetFluentMessage("contraband-approaching-starport-north-in", { ["time"] = time })
		Media.DisplayMessage(contrabandApproaching, Mentat)
	end)

	Trigger.OnAllKilledOrCaptured(HarkonnenBase, function()
		Utils.Do(Harkonnen.GetGroundAttackers(), IdleHunt)
	end)

	Trigger.OnKilled(Starport, function()
		if not Atreides.IsObjectiveCompleted(CaptureStarport) then
			ContrabandArrived = true
			UserInterface.SetMissionText(UserInterface.GetFluentMessage("starport-destroyed-no-contraband"), Atreides.Color)
			Atreides.MarkFailedObjective(CaptureStarport)
			SmugglersAttack()

			Trigger.AfterDelay(DateTime.Seconds(15), function()
				UserInterface.SetMissionText("")
			end)
		end

		if DefendStarport then
			Atreides.MarkFailedObjective(DefendStarport)
		end
	end)
	Trigger.OnDamaged(Starport, function(_, attacker)
		if Starport.Owner ~= Smuggler or attacker.IsDead or attacker.Owner ~= Atreides then
			return
		end

		if AttackNotifier <= 0 then
			AttackNotifier = DateTime.Seconds(10)
			Media.DisplayMessage(UserInterface.GetFluentMessage("do-not-destroy-starport"), Mentat)

			local defenders = Smuggler.GetGroundAttackers()
			if #defenders > 0 then
				Utils.Do(defenders, function(unit)
					unit.Guard(Starport)
				end)
			end
		end
	end)
	Trigger.OnCapture(Starport, function()
		DefendStarport = AddSecondaryObjective(Atreides, "defend-captured-starport")

		Trigger.ClearAll(Starport)
		Trigger.AfterDelay(0, function()
			Trigger.OnRemovedFromWorld(Starport, function()
				Atreides.MarkFailedObjective(DefendStarport)
			end)
		end)

		if not ContrabandArrived then
			SendContraband(Atreides)
		end
		SmugglersAttack()
	end)

	Trigger.OnKilled(HarkonnenBarracks, function()
		Atreides.MarkFailedObjective(CaptureBarracks)
	end)
	Trigger.OnDamaged(HarkonnenBarracks, function()
		if AttackNotifier <= 0 and HarkonnenBarracks.Health < HarkonnenBarracks.MaxHealth * 3/4 then
			AttackNotifier = DateTime.Seconds(10)
			Media.DisplayMessage(UserInterface.GetFluentMessage("do-not-destroy-barracks"), Mentat)
		end
	end)
	Trigger.OnCapture(HarkonnenBarracks, function()
		Media.DisplayMessage(UserInterface.GetFluentMessage("hostages-released"), Mentat)

		if DefendStarport then
			Atreides.MarkCompletedObjective(DefendStarport)
		end

		Trigger.AfterDelay(DateTime.Seconds(3), function()
			Atreides.MarkCompletedObjective(CaptureBarracks)
		end)
	end)

	SendHarkonnen()
	Actor.Create("upgrade.barracks", true, { Owner = Harkonnen })
	Actor.Create("upgrade.light", true, { Owner = Harkonnen })
	Actor.Create("upgrade.heavy", true, { Owner = Harkonnen })
	Trigger.AfterDelay(0, ActivateAI)

	Trigger.AfterDelay(DateTime.Minutes(1), function()
		Media.PlaySpeechNotification(Atreides, "Reinforce")
		Reinforcements.ReinforceWithTransport(Atreides, "carryall.reinforce", AtreidesReinforcements, AtreidesPath, { AtreidesPath[1] })
	end)

	local smugglerWaypoint = SmugglerWaypoint1.Location
	Trigger.OnEnteredFootprint({ smugglerWaypoint + CVec.New(-2, 0), smugglerWaypoint + CVec.New(-1, 0), smugglerWaypoint, smugglerWaypoint + CVec.New(1, -1), smugglerWaypoint + CVec.New(2, -1), SmugglerWaypoint3.Location }, function(a, id)
		if not Warned and a.Owner == Atreides and a.Type ~= "carryall" then
			Warned = true
			Trigger.RemoveFootprintTrigger(id)
			Media.DisplayMessage(UserInterface.GetFluentMessage("stay-away-from-starport"), UserInterface.GetFluentMessage("smuggler-leader"))
		end
	end)

	Trigger.OnEnteredFootprint({ SmugglerWaypoint2.Location }, function(a, id)
		if not Paid and a.Owner == Atreides and a.Type ~= "carryall" then
			Paid = true
			Trigger.RemoveFootprintTrigger(id)
			Media.DisplayMessage(UserInterface.GetFluentMessage("were-warned-will-pay"), UserInterface.GetFluentMessage("smuggler-leader"))
			Utils.Do(Smuggler.GetGroundAttackers(), function(unit)
				unit.AttackMove(SmugglerWaypoint2.Location)
			end)

			Trigger.AfterDelay(DateTime.Seconds(3), function()
				KillSmuggler = AddSecondaryObjective(Atreides, "destroy-smugglers-mercenaries")
				SendMercenaries()
			end)
		end
	end)

	Trigger.OnEnteredProximityTrigger(HarkonnenBarracks.CenterPosition, WDist.New(5 * 1024), function(a, id)
		if a.Owner == Atreides and a.Type ~= "carryall" then
			Trigger.RemoveProximityTrigger(id)
			Media.DisplayMessage(UserInterface.GetFluentMessage("capture-harkonnen-barracks-release-hostages"), Mentat)
			StopInfantryProduction = true
		end
	end)
end
