local Blips, JobBlips, isInMarker, hintToDisplay, onDuty, spawner, myPlate, vehicleObjInCaseofDrop, vehicleInCaseofDrop, vehicleMaxHealth =
	{}, {}, false, "no hint to display", false, 0, {}, nil, nil, nil

local PlayerPedId = PlayerPedId
local IsPedInAnyVehicle = IsPedInAnyVehicle
local GetVehiclePedIsIn = GetVehiclePedIsIn
local GetVehicleNumberPlateText = GetVehicleNumberPlateText
local GetPedInVehicleSeat = GetPedInVehicleSeat
local GetVehicleEngineHealth = GetVehicleEngineHealth

RegisterNetEvent('esx:playerLoaded', function(xPlayer)
	ESX.PlayerLoaded = true
	refreshBlips()
end)

RegisterNetEvent('esx:onPlayerLogout', function()
	ESX.PlayerLoaded = false
end)

function OpenMenu()
	local elements = {
		{ unselectable = true,   icon = "fas fa-shirt",                title = TranslateCap('cloakroom') },
		{ icon = "fas fa-shirt", title = TranslateCap('job_wear'),     value = "job_wear" },
		{ icon = "fas fa-shirt", title = TranslateCap('citizen_wear'), value = "citizen_wear" },
	}

	ESX.OpenContext("right", elements, function(menu, element)
		if element.value == "citizen_wear" then
			onDuty = false
			ESX.ShowNotification(TranslateCap('offduty'), "success")
			ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
				local isMale = skin.sex == 0

				TriggerEvent('skinchanger:loadDefaultModel', isMale, function()
					ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin)
						TriggerEvent('skinchanger:loadSkin', skin)
					end)
				end)
			end)
		elseif element.value == "job_wear" then
			onDuty = true
			ESX.ShowNotification(TranslateCap('onduty'), "success")
			ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
				if skin.sex == 0 then
					if ESX.Table.SizeOf(jobSkin.skin_male) >= 1 then
						TriggerEvent('skinchanger:loadClothes', skin, jobSkin.skin_male)
					else
						ESX.ShowNotification(TranslateCap('no_male_clothing'), "error")
					end
				else
					if ESX.Table.SizeOf(jobSkin.skin_female) >= 1 then
						TriggerEvent('skinchanger:loadClothes', skin, jobSkin.skin_female)
					else
						ESX.ShowNotification(TranslateCap('no_female_clothing'), "error")
					end
				end
			end)
		end
	end)
end

AddEventHandler('esx_jobs:action', function(job, zone, zoneKey)
	menuIsShowed = true
	local playerJob = ESX.PlayerData.job.name
	if zone.Type == "cloakroom" then
		OpenMenu()
	elseif zone.Type == "work" then
		local playerPed = PlayerPedId()

		if IsPedInAnyVehicle(playerPed, false) then
			ESX.ShowNotification(TranslateCap('foot_work'))
		else
			TriggerServerEvent('esx_jobs:startWork', zone.Item, zoneKey)
		end
	elseif zone.Type == "vehspawner" then
		local spawnPoint = nil
		local vehicle = nil

		for k, v in pairs(Config.Jobs) do
			if playerJob == k then
				for l, w in pairs(v.Zones) do
					if w.Type == "vehspawnpt" and w.Spawner == zone.Spawner then
						spawnPoint = w
						spawner = w.Spawner
					end
				end

				for m, x in pairs(v.Vehicles) do
					if x.Spawner == zone.Spawner then
						vehicle = x
					end
				end
			end
		end

		if ESX.Game.IsSpawnPointClear(spawnPoint.Pos, 5.0) then
			spawnVehicle(spawnPoint, vehicle, zone.Caution)
		else
			ESX.ShowNotification(TranslateCap('spawn_blocked'))
		end
	elseif zone.Type == "vehdelete" then
		local looping = true

		for k, v in pairs(Config.Jobs) do
			if playerJob == k then
				for l, w in pairs(v.Zones) do
					if w.Type == "vehdelete" and w.Spawner == zone.Spawner then
						local playerPed = PlayerPedId()

						if IsPedInAnyVehicle(playerPed, false) then
							local vehicle = GetVehiclePedIsIn(playerPed, false)
							local plate = GetVehicleNumberPlateText(vehicle)
							plate = string.gsub(plate, " ", "")
							local driverPed = GetPedInVehicleSeat(vehicle, -1)
							local vehicleMaxHealth = GetVehicleEngineHealth(vehicle)

							if playerPed == driverPed then
								for i = 1, #myPlate, 1 do
									if myPlate[i] == plate then
										local vehicleHealth = GetVehicleEngineHealth(vehicleInCaseofDrop)
										local giveBack = ESX.Math.Round(vehicleHealth / vehicleMaxHealth, 2)

										TriggerServerEvent('esx_jobs:caution', "give_back", giveBack, 0, 0)
										DeleteVehicle(GetVehiclePedIsIn(playerPed, false))

										if w.Teleport ~= 0 then
											ESX.Game.Teleport(playerPed, w.Teleport)
										end

										table.remove(myPlate, i)

										if vehicleObjInCaseofDrop.HasCaution then
											vehicleInCaseofDrop = nil
											vehicleObjInCaseofDrop = nil
											vehicleMaxHealth = nil
										end

										break
									end
								end
							else
								ESX.ShowNotification(TranslateCap('not_your_vehicle'))
							end
						end

						looping = false
						break
					end

					if looping == false then
						break
					end
				end
			end
			if looping == false then
				break
			end
		end
	elseif zone.Type == "delivery" then
		if Blips['delivery'] ~= nil then
			RemoveBlip(Blips['delivery'])
			Blips['delivery'] = nil
		end
		TriggerServerEvent('esx_jobs:startWork', zone.Item, zoneKey)
	end
	--nextStep(zone.GPS)
end)

function nextStep(gps)
	if gps == 0 then return end
	if Blips['delivery'] ~= nil then
		RemoveBlip(Blips['delivery'])
		Blips['delivery'] = nil
	end

	Blips['delivery'] = AddBlipForCoord(gps.x, gps.y, gps.z)
	SetBlipRoute(Blips['delivery'], true)
	ESX.ShowNotification(TranslateCap('next_point'))
end

AddEventHandler('esx_jobs:hasExitedMarker', function(zone)
	TriggerServerEvent('esx_jobs:stopWork')
	menuIsShowed = false
	isInMarker = false
end)

RegisterNetEvent('esx:setJob', function(job)
	ESX.PlayerData.job = job
	onDuty = false
	myPlate = {} -- loosing vehicle caution in case player changes job.
	spawner = 0
	deleteBlips()
	refreshBlips()
end)

function deleteBlips()
	if JobBlips[1] ~= nil then
		for i = 1, #JobBlips, 1 do
			RemoveBlip(JobBlips[i])
			JobBlips[i] = nil
		end
	end
end

function refreshBlips()
	local zones = {}
	local blipInfo = {}
	
	while not ESX.PlayerLoaded do
	    Wait(500)
	end

	local playerJob = ESX.PlayerData.job?.name

	for jobKey, jobValues in pairs(Config.Jobs) do
		if jobKey == playerJob then
			for zoneKey, zoneValues in pairs(jobValues.Zones) do
				if not zoneValues.Blip then goto continue end
				local _Pos = {}
				if not (zoneValues.Zone) then
					_Pos = zoneValues.Pos
				end
				TriggerEvent("izone:getZoneCenter", zoneValues.Zone, function(_center)
					if (_center) then
						_Pos = _center
					end
				end)
				local blip = AddBlipForCoord(_Pos.x, _Pos.y, _Pos.z)
				SetBlipSprite(blip, jobValues.BlipInfos.Sprite)
				SetBlipDisplay(blip, 4)
				SetBlipScale(blip, 0.8)
				SetBlipCategory(blip, 3)
				SetBlipColour(blip, jobValues.BlipInfos.Color)
				SetBlipAsShortRange(blip, true)

				BeginTextCommandSetBlipName("STRING")
				AddTextComponentSubstringPlayerName(zoneValues.Name)
				EndTextCommandSetBlipName(blip)
				table.insert(JobBlips, blip)

				::continue::
			end
		end
	end
end


function spawnVehicle(spawnPoint, vehicle, vehicleCaution)
	hintIsShowed = false
	TriggerServerEvent('esx_jobs:caution', 'take', vehicleCaution, spawnPoint, vehicle)
end

RegisterNetEvent('esx_jobs:spawnJobVehicle', function(spawnPoint, vehicle)
	local playerPed = PlayerPedId()

	ESX.Game.SpawnVehicle(vehicle.Hash, spawnPoint.Pos, spawnPoint.Heading, function(spawnedVehicle)
		if vehicle.Trailer ~= "none" then
			ESX.Game.SpawnVehicle(vehicle.Trailer, spawnPoint.Pos, spawnPoint.Heading, function(trailer)
				AttachVehicleToTrailer(spawnedVehicle, trailer, 1.1)
			end)
		end

		-- save & set plate
		local plate = 'WORK' .. math.random(100, 900)
		SetVehicleNumberPlateText(spawnedVehicle, plate)
		table.insert(myPlate, plate)
		plate = string.gsub(plate, " ", "")

		TaskWarpPedIntoVehicle(playerPed, spawnedVehicle, -1)

		if not vehicle.HasCaution then return end
		vehicleInCaseofDrop = spawnedVehicle
		vehicleObjInCaseofDrop = vehicle
		vehicleMaxHealth = GetVehicleEngineHealth(spawnedVehicle)
	end)
end)

-- Display markers (only if on duty and the player's job ones)
CreateThread(function()
	while true do
		local Sleep = 1500
		local zones = {}

		if ESX.PlayerLoaded then
			local playerJob = ESX.PlayerData.job.name

			if playerJob then
				for k, v in pairs(Config.Jobs) do
					if playerJob == k then
						Sleep = 0
						zones = v.Zones
					end
				end

				local coords = GetEntityCoords(PlayerPedId())
				for k, v in pairs(zones) do
					if onDuty or v.Type == "cloakroom" then
						if (v.Zone) then
							TriggerEvent("izone:getZoneCenter", v.Zone, function(center)
								if (not (center == nil)) then
									if (v.Marker ~= -1 and #(coords - center) < Config.DrawDistance) then
										Sleep = 0
										DrawMarker(v.Marker, center.x, center.y, center.z - 1, 0.0, 0.0, 0.0, 0, 0.0, 0.0,
											v.Size.x, v.Size.y, v.Size.z, v.Color.r, v.Color.g, v.Color.b, 100, false,
											true,
											2, false, false, false, false)
									end
								end
							end)
						else
							local Pos = vector3(v.Pos.x, v.Pos.y, v.Pos.z)
							if (v.Marker ~= -1 and #(coords - Pos) < Config.DrawDistance) then
								Sleep = 0
								DrawMarker(v.Marker, v.Pos.x, v.Pos.y, v.Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, v.Size.x,
									v.Size.y, v.Size.z, v.Color.r, v.Color.g, v.Color.b, 100, false, true, 2, false,
									false,
									false, false)
							end
						end
					end
				end
			end
		end
		Wait(Sleep)
	end
end)

-- Display public markers
CreateThread(function()
	while true do
		local Sleep = 1500
		local coords = GetEntityCoords(PlayerPedId())
		for k, v in pairs(Config.PublicZones) do
			if (v.Marker ~= -1 and #(coords - v.Pos) < Config.DrawDistance) then
				Sleep = 0
				DrawMarker(v.Marker, v.Pos.x, v.Pos.y, v.Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, v.Size.x, v.Size.y, v.Size.z,
					v.Color.r, v.Color.g, v.Color.b, 100, false, true, 2, false, false, false, false)
			end
		end
		Wait(Sleep)
	end
end)

-- Activate public marker
CreateThread(function()
	while true do
		local Sleep  = 1500
		local coords = GetEntityCoords(PlayerPedId())

		for k, v in pairs(Config.PublicZones) do
			if #(coords - v.Pos) < v.Size.x / 2 then
				Sleep = 0
				ESX.ShowHelpNotification(v.Hint)
				hintIsShowed = true
				if IsControlJustReleased(0, 38) then
					ESX.Game.Teleport(PlayerPedId(), v.Teleport)
				end
			end
		end

		Wait(Sleep)
	end
end)

-- Activate menu when player is inside marker
CreateThread(function()
	while true do
		local Sleep = 500

		if ESX.PlayerLoaded then
			local playerJob = ESX.PlayerData.job.name

			if playerJob and playerJob ~= 'unemployed' then
				local zones = nil
				local job = nil

				for k, v in pairs(Config.Jobs) do
					if playerJob == k then
						Sleep = 0
						job = v
						zones = v.Zones
					end
				end

				if zones then
					local coords      = GetEntityCoords(PlayerPedId())
					local currentZone = nil
					local zone        = nil
					local lastZone    = nil

					for k, v in pairs(zones) do
						-- If we defined a zone from iZone
						if v.Zone then
							TriggerEvent("izone:isPlayerInZone", v.Zone, function(isIn)
								if isIn then
									Sleep       = 0
									isInMarker  = true
									currentZone = k
									zone        = v
									return
								else
									isInMarker = false
								end
							end)
							-- Because we were in a routine
							if isInMarker then
								break
							end
							-- Else use radius defined from center
						else
							local Pos = vector3(v.Pos.x, v.Pos.y, v.Pos.z)
							if #(coords - Pos) < v.Size.x then
								Sleep       = 0
								isInMarker  = true
								currentZone = k
								zone        = v
								break
							else
								isInMarker = false
							end
						end
					end

					if IsControlJustReleased(0, 38) and not menuIsShowed and isInMarker then
						if onDuty or zone.Type == "cloakroom" then
							TriggerEvent('esx_jobs:action', job, zone, currentZone)
						end
					end

					-- hide or show top left zone hints
					if isInMarker and not menuIsShowed then
						hintIsShowed = true
						if (onDuty or zone.Type == "cloakroom") and zone.Type ~= "vehdelete" then
							if zone.Hint then
								hintToDisplay = zone.Hint
								ESX.ShowHelpNotification(hintToDisplay)
							end
						elseif zone.Type == "vehdelete" and (onDuty) then
							local playerPed = PlayerPedId()

							if IsPedInAnyVehicle(playerPed, false) then
								local vehicle = GetVehiclePedIsIn(playerPed, false)
								local driverPed = GetPedInVehicleSeat(vehicle, -1)
								local plate = GetVehicleNumberPlateText(vehicle)
								plate = string.gsub(plate, " ", "")

								if playerPed == driverPed then
									for i = 1, #myPlate, 1 do
										if myPlate[i] == plate then
											hintToDisplay = zone.Hint
											break
										end
									end
								else
									hintToDisplay = TranslateCap('not_your_vehicle')
									ESX.ShowHelpNotification(hintToDisplay)
								end
							else
								hintToDisplay = TranslateCap('in_vehicle')
								ESX.ShowHelpNotification(hintToDisplay)
							end
							hintIsShowed = true
						elseif onDuty and zone.Spawner ~= spawner then
							hintToDisplay = TranslateCap('wrong_point')
							ESX.ShowHelpNotification(hintToDisplay)
						end
					end

					if isInMarker and not hasAlreadyEnteredMarker then
						hasAlreadyEnteredMarker = true
					end

					if not isInMarker and hasAlreadyEnteredMarker then
						hasAlreadyEnteredMarker = false
						TriggerEvent('esx_jobs:hasExitedMarker', zone)
					end
				end
			end
		end
		Wait(Sleep)
	end
end)

if Config.RequestIPL then
	CreateThread(function()
		-- Slaughterer
		RemoveIpl("CS1_02_cf_offmission")
		RequestIpl("CS1_02_cf_onmission1")
		RequestIpl("CS1_02_cf_onmission2")
		RequestIpl("CS1_02_cf_onmission3")
		RequestIpl("CS1_02_cf_onmission4")
		-- Tailor
		RequestIpl("id2_14_during_door")
		RequestIpl("id2_14_during1")
	end)
end

if ESX.PlayerLoaded then refreshBlips() end
