local PLUGIN = PLUGIN

--[[CLIENT SIDE]]
function PLUGIN:PreRender()
	if not ix.config.Get("leanEnabled", true) then return end
	TFALeanModel()
end

local minvec = Vector(-6, -6, -6)
local maxvec = Vector(6, 6, 6)

local function filterfunc(ent)
	if (ent:IsPlayer() or ent:IsNPC() or ent:IsWeapon() or ent:GetClass() == "rpg_missile" or ent:GetClass() == "crossbow_bolt" or ent:GetClass() == "npc_grenade_frag" or ent:GetClass() == "apc_missile" or ent:GetClass() == "viewmodel_predicted") then
		return false
	else
		return true
	end
end

local function bestcase(pos, endpos, ply)
	local off = endpos - pos
	local trace = {}
	trace.start = pos
	trace.endpos = pos + off
	trace.mask = MASK_SOLID
	trace.filter = filterfunc
	trace.ignoreworld = false
	trace.maxs = maxvec
	trace.mins = minvec
	local traceres = util.TraceHull(trace)

	return pos + off:GetNormalized() * math.Clamp(traceres.Fraction, 0, 1) * off:Length()
end

function LeanCalcView(ply, pos, angles, fov)
	local view = {}
	view.origin = pos
	view.angles = angles
	view.fov = fov
	if not ply:Alive() or ply:Health() <= 0 then return view end
	
	local status = ply.TFALean or 0
	local leanOffset = ix.config.Get("leanOffset", 16)
	local rollAngle = ix.config.Get("leanRollAngle", 15)
	local off = Vector(0, status * -leanOffset, 0)
	off:Rotate(angles)
	view.angles:RotateAroundAxis(view.angles:Forward(), status * rollAngle)
	view.origin = bestcase(view.origin, view.origin + off, ply)

	return view
end

local ISLEANINGCV = false

function PLUGIN:CalcView(ply, pos, angles, fov)
	if ISLEANINGCV then return end
	if not ix.config.Get("leanEnabled", true) then return end
	if GetViewEntity() ~= ply then return end
	if not ply:Alive() then return end
	if ply:InVehicle() then return end
	
	ISLEANINGCV = true
	local preTableRaw = hook.Run("CalcView", ply, pos, angles, fov)
	ISLEANINGCV = false

	local preOrigin, preAngles, preFov
	if type(preTableRaw) == "table" then
		preOrigin = rawget(preTableRaw, "origin") or pos
		preAngles = rawget(preTableRaw, "angles") or angles
		preFov    = tonumber(rawget(preTableRaw, "fov")) or fov
	else
		preOrigin = pos
		preAngles = angles
		preFov    = fov
	end
	local preTable = { origin = preOrigin, angles = preAngles, fov = preFov }
	
	local finalTable = LeanCalcView(ply, preTable.origin, preTable.angles, preTable.fov)
	
	for k, v in pairs(preTable) do
		if finalTable[k] == nil and (k == "origin" or k == "angles" or k == "fov" or k == "drawviewer" or k == "znear" or k == "zfar") then
			rawset(finalTable, k, v)
		end
	end

	return finalTable
end

local ISLEANINGCV_VM = false

function LeanCalcVMView(wep, vm, oldPos, oldAng, pos, ang)
	if ISLEANINGCV_VM then return end
	local ply = LocalPlayer()
	if GetViewEntity() ~= ply then return end

	if not ply.tfacastoffset or ply.tfacastoffset <= 0.001 then
		local status = ply.TFALean or 0

		if math.abs(status) > 0.001 then
			local leanOffset = ix.config.Get("leanOffset", 16)
			local off = Vector(0, status * -leanOffset, 0)
			off:Rotate(ang)
			ang:RotateAroundAxis(ang:Forward(), status * 12 * (wep.ViewModelFlip and -1 or 1))
			pos = bestcase(pos, pos + off, ply)
			ISLEANINGCV_VM = true
			local tpos, tang = hook.Run("CalcViewModelView", wep, vm, oldPos, oldAng, pos, ang)
			ISLEANINGCV_VM = false

			if tpos then
				pos = tpos
			end

			if tang then
				ang = tang
			end

			return pos, ang
		end
	end
end

function PLUGIN:CalcViewModelView(wep, vm, oldPos, oldAng, pos, ang)
	if not ix.config.Get("leanEnabled", true) then return end
	return LeanCalcVMView(wep, vm, oldPos, oldAng, pos, ang)
end
