#include "driver_banger_base.lua"

-- ===================================
IS_DRIVE 			= true
DO_TICK 			= true


function init()
	local vehicle_id = FindDrivableVehicle()

	-- If cant find vehicle
	if trigger == 0 or not vehicle_id or vehicle_id == 0 then
		DO_TICK = false
		return
	end

	vehicle = c_vehicle:new(vehicle_id)
	vehicle:SetSteeringController({1.0, 0.9, 0.5})
	vehicle:SetAccelerationController({})

	-- ===================================
	-- Driver params:
	try_other_way 			= 0
	try_to_make_distance 	= false
	next_wp 				= 0
	prev_wp 				= 0
	start_line_pos 			= {}
	end_line_pos 			= {}
	current_time_to_respawn = TIME_RESPAWN_CANT_REACH_WP
	current_state 			= ""
	ignore_vehicles			= false
	IS_PID_STEERING 		= true
	base_veh_params 		= GetVehicleParams(vehicle.id)
	topspeed				= base_veh_params["topspeed"]
	current_max_velocity 	= topspeed
	-- cheat_skip_respawn		= false
	invisible				= false

	-- ===================================
	-- Waypoints:

	all_waypoints 		= {}
	waypoints_loc		= {}
	path_id				= 0
	SetRaceSettings()
	checkpoints 	= FindCheckpoints()

	-- ===================================
	-- Waypoint params:
	NEXT_MAX_VELOCITY 	= current_max_velocity
	MAX_VELOCITY 		= current_max_velocity
	is_next_turn 		= false

    RegisterListenerTo(EVENTS.GAME_OVER, "OnRaceOver")
	RegisterListenerTo(EVENTS.BANGER_RESPAWN, "RespawnPlayerAI")
	RegisterListenerTo(EVENTS.STATS_FILLED, "StatsFilled")
	RegisterListenerTo(EVENTS.WAIT_EVENT, "TriggerWaitEvent")

	ToOtherState(DRIVER_BANGER_STATES.wait)
end

function update(dt)
	timer_manager:Tick(dt)

	 -- fix error attempting to altering iterated table
	for i = 1, #TIMER_CALLBACKS do
		if TIMER_CALLBACKS[i]() then
			TIMER_CALLBACKS[i] = nil
		end
	end

	if current_state == DRIVER_BANGER_STATES.wait or
		not DO_TICK or current_state == DRIVER_BANGER_STATES.dead or
		next_wp == 0 then

		return
	end

	vehicle:Tick(dt)

	-- if cheat_skip_respawn then
	-- 	SetBool("level.cheat_skip.last_time", true)
	-- end

	CheckWayPoint(dt)
	CheckSlippery()

	if current_state == DRIVER_BANGER_STATES.drive then
		-- Drive vehicle to race line
		CheckNeedToRecover(dt)
		NewTarget()
		if not ignore_vehicles then
			MakeDistanceWithVehicles()
		end
		AvoidObstacles(dt)

	elseif current_state == DRIVER_BANGER_STATES.recover then
		-- Try to recover to race line or respawn
		if vehicle:GetVehicleVelocity() > 15 then
			ToOtherState(DRIVER_BANGER_STATES.drive)

		elseif current_time_before_respawn < 0 then
			Respawn()

		elseif current_time_to_rec < 0 then
			Recovery()
		end

		current_time_before_respawn = current_time_before_respawn - dt
		current_time_to_rec = current_time_to_rec - dt

	end

	Solve(dt)

	if GetVehicleHealth(vehicle.id) == 0 then
		ToOtherState(DRIVER_BANGER_STATES.dead)
		DeleteAllListeners()
	end
end

function tick()
	DriveAI()
end

-- ===================================
-- Timer, events and options functions
-- ===================================

function OnRaceOver()
    UnregisterListener(EVENTS.GAME_OVER, "OnRaceOver")
	vehicle:Tick()
	local closestCP = FindClosestCP()
	ChoosePath(closestCP)
	SetNextWpAfterRespawn(closestCP)
	SetNewNextWP(FindClosestWP())
	ToOtherState(DRIVER_BANGER_STATES.drive)
    if GetBool("level.debug_enabled") then
	    TriggerEvent(EVENTS.AI_RUBBERBAND, true)
    end
end

function FindClosestCP()
	local closest_cp, min_length = 0, 100000
	local vehicle_pos = GetVehicleTransform(vehicle.id).pos
	for i = 1, #checkpoints do
		local cp_pos = checkpoints[i].t.pos
		local length = VecLength(VecSub(vehicle_pos, cp_pos))
		if length < min_length then
			closest_cp, min_length = i, length
		end
	end

	return closest_cp
end

function StatsFilled()
	UnregisterListener(EVENTS.STATS_FILLED, "StatsFilled")
	ai_index = cRegistry:GetVehiclePlayer(vehicle.id) -- AI index in level registry
end

function DeleteAllListeners()
    UnregisterListener(EVENTS.GAME_OVER, "OnRaceOver")
	UnregisterListener(EVENTS.BANGER_RESPAWN, "RespawnPlayerAI")
	UnregisterListener(EVENTS.STATS_FILLED, "StatsFilled")
	UnregisterListener(EVENTS.WAIT_EVENT, "TriggerWaitEvent")
end

function ClearTickTimers()
	timer_manager:ClearTimer(TIMER_TO_CHECK_PLAYER_PLACE)
	vehicle.control.drive_multiplier = 1.0
end

function RespawnPlayerAI(ai_handle_or_from_timer)
	if current_state == DRIVER_BANGER_STATES.wait then return end

	Respawn(ai_handle_or_from_timer)
end