include("shared.lua")
include("wol_config.lua")

game.AddParticles("particles/wol_money_effects.pcf")

surface.CreateFont("WOL_Display_Large", {font = "DSEG14 Modern", size = 125, weight = 500, blursize = 0, scanlines = 0, antialias = true})
surface.CreateFont("WOL_Display_Smallest", {font = "DSEG14 Modern", size = 35, weight = 500, blursize = 0, scanlines = 0, antialias = true})
surface.CreateFont("WOL_Display_Smallest_2", {font = "Roboto", size = 90, weight = 1300, blursize = 0, scanlines = 0, antialias = true})
surface.CreateFont("WOL_Display_Smallest_3", {font = "Roboto", size = 25, weight = 1300, blursize = 0, scanlines = 0, antialias = true})

local use_font = system.IsWindows() and "Tahoma" or "Verdana"
surface.CreateFont("WOL_Display_Info", {font = use_font, size = 18, weight = 600, blursize = 0, scanlines = 0})

local LeverPulled = 35
local LeverBoneID = 3
local BonusWheelBoneID = 7
local ButtonBoneID = 8
local BonusWheelSpinTime = 10

local function HSVToRGB(h, s, v, a)
	local r, g, b
	local i = math.floor(h * 6)
	local f = h * 6 - i
	local p = v * (1 - s)
	local q = v * (1 - f * s)
	local t = v * (1 - (1 - f) * s)
	i = i % 6
	if i == 0 then
		r, g, b = v, t, p
	elseif i == 1 then
		r, g, b = q, v, p
	elseif i == 2 then
		r, g, b = p, v, t
	elseif i == 3 then
		r, g, b = p, q, v
	elseif i == 4 then
		r, g, b = t, p, v
	elseif i == 5 then
		r, g, b = v, p, q
	end
	return Color(r * 255, g * 255, b * 255, 255)
end

function ENT:InitializeReels()
	self.reels = self.reels or {}
	local reload = false
	if !IsValid(self.reels[1]) then
		reload = true
		self.reels[1] = self:GetReelOne()
	end
	if !IsValid(self.reels[2]) then
		reload = true
		self.reels[2] = self:GetReelTwo()
	end
	if !IsValid(self.reels[3]) then
		reload = true
		self.reels[3] = self:GetReelThree()
	end
	if reload then
		for i = 1, 3 do
			if !IsValid(self.reels[i]) then return end
			self.reels[i]:SetSkin(1)
		end
	end
end

function ENT:Initialize()
	self.LeverAnimating = false
	self:InitializeReels()
	self.BonusHue = 0
	self.BonusSoundPlaying = false
	self.JackpotIsPlaying = false
	self.DecendingJackpotAmount = 0
	self.PreviousJackpot = 0
	self.IsPlayingButtonAnimation = false
	self:SetAutomaticFrameAdvance(true)
	self.BonusWheelSpinning = false
	self.BonusWheelPreviousAngle = 0
	self.BonusWheelAngle = 0
	self.BonusWheelTarget = 0
	self.FaceSinceLastSound = 1
	self.TimeSinceClickSound = CurTime()
	self.PlayBounsLights = false

	timer.Simple(1, function()
		if !IsValid(self) then return end
		self:InitializeReels()
	end)
end

function ENT:PlayBonusSound()
	sound.PlayFile("sound/wol/bonus sound.mp3", "3d", function(station)
		if !IsValid(self) then return end
		if IsValid(station) then 
			self.BonusSound = station
			self.BonusSound:SetPos(self:GetPos())
			self.BonusSound:Set3DFadeDistance(100, 800)
			self.BonusSound:SetVolume(0.7)
			station:Play() 
			self.BonusSoundPlaying = true
		end
	end)
end

function ENT:PlayJackpotSound()
	sound.PlayFile("sound/wol/jackpot_sound.mp3", "3d", function(station)
		if !IsValid(self) then return end
		if IsValid(station) then 
			self.BonusSound = station
			self.BonusSound:SetPos(self:GetPos())
			self.BonusSound:Set3DFadeDistance(100, 1750)
			self.BonusSound:SetVolume(1)
			station:Play() 
			self.BonusSoundPlaying = true
		end
	end)
end

local local_ply, pos
function ENT:Draw()
	self:DrawModel()
	local_ply = local_ply or LocalPlayer()
	pos = self:GetPos()
	local tb = self:GetTable()
	self:VisualCutoff(local_ply, pos, tb)
	if tb.Distance < 360000 then
		local ang = self:GetAngles()
		local pos = self:GetPos()
		pos = pos + (ang:Forward() * 27.2)
		pos = pos + (ang:Up() * 62.7)
		pos = pos + (ang:Right() * -14)
		ang:RotateAroundAxis(ang:Up(), 90)
		ang:RotateAroundAxis(ang:Forward(), 85)
		cam.Start3D2D(pos , ang, 0.02)
			draw.SimpleText("~~", "WOL_Display_Smallest", 0, 0, Color(30,30,30,150), 2, 1)
			local spins = self:GetBonusSpins()
			if spins < 10 then
				draw.SimpleText("0"..spins, "WOL_Display_Smallest", 0, 0, Color(220,220,220,255), 2, 1)
			else
				draw.SimpleText(spins, "WOL_Display_Smallest", 0, 0, Color(220,220,220,255), 2, 1)
			end
			draw.SimpleText("~~~~~~~~", "WOL_Display_Smallest", 19, -230, Color(30,30,30,150), 2, 1)
			draw.SimpleText(self:GetLastWin(), "WOL_Display_Smallest", 19, -230, Color(220,220,220,255), 2, 1)
		cam.End3D2D()	
		ang = self:GetAngles()
		pos = self:GetPos()
		pos = pos + (ang:Forward() * 26)
		pos = pos + (ang:Up() * 90.35)
		pos = pos + (ang:Right() * -14.3)
		ang:RotateAroundAxis(ang:Up(), 90)
		ang:RotateAroundAxis(ang:Forward(), 90)
		cam.Start3D2D(pos, ang, 0.02)
			draw.SimpleText("~~~~~~~~~~~~~~", "WOL_Display_Large", 0, 0, Color(30,30,30,150), 2, 1)
			if tb.JackpotIsPlaying and timer.Exists(self:EntIndex().."_Jackpot") and tb.PreviousJackpot then
				tb.DecendingJackpotAmount = Lerp(1 - (timer.TimeLeft(self:EntIndex().."_Jackpot") / 42), tb.PreviousJackpot, 0)
				draw.SimpleText(string.Comma(math.floor(tb.DecendingJackpotAmount)), "WOL_Display_Large", 0, 0, Color(255,215,0,255), 2, 1)
			else
				draw.SimpleText(string.Comma(self:GetJackpot()), "WOL_Display_Large", 0, 0, Color(255,215,0,255), 2, 1)
			end
		cam.End3D2D()
		for i = 1 , 20 do
			if i != 1 then
				ang = self:GetAngles()
				pos = self:GetPos()
				pos = pos + (ang:Forward() * 21.1)
				pos = pos + (ang:Up() * 114.35)
				ang:RotateAroundAxis(ang:Up(), 90)
				ang:RotateAroundAxis(ang:Forward(), 90)
				ang:RotateAroundAxis(self:GetAngles():Forward(), ((360 / 20) * (i - 1)) + 90 + tb.BonusWheelAngle)
				cam.Start3D2D(pos, ang, 0.02)
					draw.SimpleText("$"..string.Comma(WOL.BONUS_ITEMS[i].cash), "WOL_Display_Smallest_2", 590,  -4 , Color(0,0,0,255), 2, 1)
				cam.End3D2D()
			end
		end
	end
end

function ENT:VisualCutoff(local_ply, pos, tb)
	local cur_time = CurTime()
	if (tb.LastDistanceCheck or 0) > cur_time then return end
	tb.LastDistanceCheck = cur_time + 0.1
	tb.Distance = pos:DistToSqr(local_ply:EyePos())
end

local function LerpAngleCustom(value, start, _end)
    local min = 0
    local max = 360
    local half = math.abs((max - min) / 2)
    local retval = 0.0
    local diff = 0.0
    if ((_end - start) < -half) then
        diff = ((max - start) + _end) * value
        retval = start + diff
    elseif ((_end - start) > half) then
        diff = -((max - _end) + start) * value
        retval = start + diff
    else 
    	retval = start + (_end - start) * value
    end
    return retval
end

local function Hermite(value, start, _end)
    return Lerp(value * value * (3 - 2 * value), start, _end)
end

function ENT:Think()
	local tb = self:GetTable()
	if tb.BonusSound then
		tb.BonusSound:SetVolume(0.7)
	end
	if tb.LeverAnimating then
		local total_time = 1
		local time_left = timer.TimeLeft(self:EntIndex().."_LeverAnimation")
		if !time_left then return end
		time_left = time_left * 2
		local angle = Angle(0,0,0)
		if time_left / 2 < total_time / 2 then
			angle.r = Hermite(time_left, 0, LeverPulled)
		else
			angle.r = Hermite(time_left - (total_time), LeverPulled, 0)
		end
		self:ManipulateBoneAngles(LeverBoneID, angle)
	end
	if tb.BonusWheelSpinning and timer.Exists(self:EntIndex().."_BonusWheel") then
		tb.BonusWheelAngle = Hermite(1 - (timer.TimeLeft(self:EntIndex().."_BonusWheel") / 10), tb.BonusWheelPreviousAngle, tb.BonusWheelTarget)
		self:ManipulateBoneAngles(BonusWheelBoneID, Angle(0, tb.BonusWheelAngle, 0))
		local norm_angle = (tb.BonusWheelAngle - 9) % 360
		if norm_angle < 0 then
			norm_angle = norm_angle + 360
		end
		local current_face = math.floor(norm_angle / 18)
		if current_face != tb.FaceSinceLastSound then
			tb.FaceSinceLastSound = current_face
			if CurTime() - tb.TimeSinceClickSound >= 0.02 then
				sound.Play("wol/bonus_click.ogg", self:GetPos() + Vector(0, 0, 75), 60, math.random(100,108), 0.9)
				tb.TimeSinceClickSound = CurTime()
			end
		end
	end
	if tb.PlayBounsLights then
		local color = HSVToRGB(tb.BonusHue % 360, 0.5, 1)
		local dlight = DynamicLight(self:EntIndex())
		if dlight then
			dlight.pos = self:GetPos() + Vector(0, 0, 100) + (self:GetAngles():Forward() * 40)
			dlight.r = color.r
			dlight.g = color.g
			dlight.b = color.b
			dlight.brightness = 3
			dlight.Decay = 1000
			dlight.Size = 256
			dlight.DieTime = CurTime() + 1
		end
		tb.BonusHue = tb.BonusHue + (1 * FrameTime())
		debugoverlay.Sphere(self:GetPos() + Vector(0, 0, 75) + (self:GetAngles():Forward() * 35), 25, 1)
	else
		if tb.BonusSound and !tb.BonusSoundPlaying then
			tb.BonusSound:Stop()
			tb.BonusSound = nil
		end
	end
end

function ENT:SpinReels()
	for _, v in ipairs(self.reels) do
		if !IsValid(v) or !v.Spin then continue end
		v:Spin()
	end
end

function ENT:SpinBonusWheel(target_item)
	target_item = 360 - (18 * (target_item - 1))
	self.BonusWheelSpinning = true
	self.BonusWheelTarget = target_item + (360 * 5)
	timer.Create(self:EntIndex().."_BonusWheel", BonusWheelSpinTime, 1, function()
		if !IsValid(self) then return end
		self.BonusWheelSpinning = false
		self.BonusWheelPreviousAngle = self.BonusWheelAngle % 360
	end)
end

function ENT:StopReel(reel, item)
	local reel = self.reels[reel]
	if !IsValid(reel) then return end
	reel:StopReel(item)
end

function ENT:TriggerLeverAnimation()
	self.LeverAnimating = true
	timer.Create(self:EntIndex().."_LeverAnimation", 1, 1, function()
		if !IsValid(self) then return end
		self.LeverAnimating = false
	end)
end

function ENT:Flash()
	for _,v in ipairs(self.reels) do
		if !IsValid(v) or !v.Flash then continue end
		v:Flash()
	end
end

local paymaterial = Material("materials/wol_ui/paytable.png")
local f
local function CreatePayTableUI()
	if IsValid(f) then return end
	f = vgui.Create("DFrame")
	f:SetSize(700, 500)
	f:Center()
	f:SetDraggable(false)
	f:SetTitle("")
	f.Paint = function(s, w, h)
		surface.SetDrawColor(Color(255, 255, 255))
		surface.SetMaterial(paymaterial)
		surface.DrawTexturedRect(0, 0, w, h)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.ThreeBonus), "WOL_Display_Smallest_3", 220, 200, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.TwoBonus), "WOL_Display_Smallest_3", 220, 238, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.OneBonus), "WOL_Display_Smallest_3", 220,284,Color(40,40,40,255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.ThreeRaspberry), "WOL_Display_Smallest_3", 220, 334, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.ThreeCoins), "WOL_Display_Smallest_3", 220, 384, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.TwoCoins), "WOL_Display_Smallest_3", 220, 434, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.ThreeBar2), "WOL_Display_Smallest_3", 585, 200, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.ThreeBar), "WOL_Display_Smallest_3", 585, 238, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.ThreeSeven), "WOL_Display_Smallest_3", 585, 278, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.ThreeDiamonds), "WOL_Display_Smallest_3", 585, 340, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.TwoDiamonds), "WOL_Display_Smallest_3", 585, 386, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.winning.OneDiamond), "WOL_Display_Smallest_3", 585, 430, Color(40, 40, 40, 255), 0, 1)
		draw.SimpleText("$"..string.Comma(WOL_CONFIG.PricePerSpin), "WOL_Display_Smallest_3", 302, 478, Color(40, 40, 40, 255), 0, 1)
	end
	f:MakePopup()
	f:ParentToHUD()
end
concommand.Add("wheelofluck", CreatePayTableUI)

hook.Add("OnPlayerChat", "WOL_OpenMenu", function(ply, text)
	if string.lower(text) == "!wheelofluck" then
		if ply != LocalPlayer() then return true end
		CreatePayTableUI()
		return true
	end
end)

local local_ply, tr, ent
local function DrawInfo()
	local_ply = local_ply or LocalPlayer()
	tr = local_ply:GetEyeTrace()
	ent = tr.Entity
	if IsValid(ent) and ent:GetClass() == "wheel_of_luck" and !ent.LeverAnimating then
		local distance = local_ply:GetPos():DistToSqr(tr.HitPos)
		if distance <= 8100 then
			draw.SimpleTextOutlined("["..((input.LookupBinding("+use") or "[BENUTZEN]"):upper()).."] Wheel of Luck spielen ($"..string.Comma(WOL_CONFIG.PricePerSpin)..")", "WOL_Display_Info", ScrW() / 2, ScrH() / 2 + 20, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 1, color_black)
		end
	end
end
hook.Add("HUDPaint", "WOL_DrawInfo", DrawInfo)

net.Receive("WOL_BeginSpin", function()
	local e = net.ReadEntity()
	if IsValid(e) and e.SpinReels then
		e:SpinReels()
	end
end)

net.Receive("WOL_BeginBonusSpin", function()
	local e = net.ReadEntity()
	if IsValid(e) and e.SpinBonusWheel then
		e:SpinBonusWheel(net.ReadInt(16))
		e:ResetSequence(1)
		e:SetCycle(0)
		e:SetPlaybackRate(1)
		timer.Simple(3, function()
			if !IsValid(e) then return end
			e:ResetSequence(0)
			e:SetCycle(0)
		end)
	end
end)

net.Receive("WOL_TriggerLever" , function()
	local e = net.ReadEntity()
	if IsValid(e) and e.TriggerLeverAnimation then
		e:TriggerLeverAnimation()
	end
end)

net.Receive("WOL_StopReel", function()
	local index = net.ReadInt(6)
	local item = net.ReadInt(7)
	local e = net.ReadEntity()
	if IsValid(e) and e.StopReel then
		e:StopReel(index, item)
	end
end)

net.Receive("WOL_FlashLights", function()
	local e = net.ReadEntity()
	if IsValid(e) and e.reels then
		local winning_reels = net.ReadTable()
		for k, v in pairs(winning_reels) do
			if v then
				e.reels[k]:Flash()
			end
		end
	end
end)

net.Receive("WOL_BonusSound", function()
	local e = net.ReadEntity()
	if IsValid(e) and e.PlayBonusSound then
		local num = net.ReadBool()
		if num then
			e:PlayBonusSound()
			timer.Simple(1.66, function()
				if !IsValid(e) then return end
				e.PlayBounsLights = true
				if IsValid(e.reels[1]) then
					e.reels[1].targetSkin = 3 
					e.reels[1]:SetSkin(3)
				end
				if IsValid(e.reels[2]) then
					e.reels[2].targetSkin = 1
					e.reels[2]:SetSkin(1)
				end
				if IsValid(e.reels[3]) then
					e.reels[3].targetSkin = 3
					e.reels[3]:SetSkin(3)
				end
				timer.Create(e:EntIndex().."_BonusLights", 0.476, 0, function()
					if !IsValid(e) then return end
					if e.PlayBounsLights then
						for _, v in ipairs(e.reels) do
							if !IsValid(v) then continue end
							if v:GetSkin() != 1 then
								v:SetSkin(1)
								v.targetSkin = 1
							else
								v:SetSkin(3)	
								v.targetSkin = 3
							end
						end
					else
						timer.Remove(e:EntIndex().."_BonusLights")
						for _,v in ipairs(e.reels) do
							v:SetSkin(1)
							v.targetSkin = 1
						end
					end
				end)
			end)
		else
			e.PlayBounsLights = false
			timer.Remove(e:EntIndex().."_BonusLights")
			for _, v in ipairs(e.reels) do
				if !IsValid(v) then continue end
				v.targetSkin = 1
				v:SetSkin(1)
			end
			e.BonusSoundPlaying = false
		end
	end
end)

net.Receive("WOL_TriggerJackpot" , function()
	local e = net.ReadEntity()
	local num = net.ReadBool()
	if IsValid(e) and e.PlayJackpotSound then
		if num then
			e:PlayJackpotSound()
			e.DecendingJackpotAmount = e:GetJackpot()
			e.PreviousJackpot = e:GetJackpot()
			for _,v in ipairs(e.reels) do
				if !IsValid(v) then continue end
				v:SetSkin(1)
				v.targetSkin = 1
			end
			timer.Simple(2.28, function()
				if !IsValid(e) then return end
				e.JackpotIsPlaying = true
				timer.Create(e:EntIndex().."_Jackpot", 42, 1 , function()
					if !IsValid(e) then return end
					e.JackpotIsPlaying = false
					e.DecendingJackpotAmount = 0
				end)
				e.PlayBounsLights = true
				if IsValid(e.reels[1]) then
					e.reels[1].targetSkin = 3 
					e.reels[1]:SetSkin(3)
				end
				if IsValid(e.reels[2]) then
					e.reels[2].targetSkin = 1
					e.reels[2]:SetSkin(1)
				end
				if IsValid(e.reels[3]) then
					e.reels[3].targetSkin = 3
					e.reels[3]:SetSkin(3)
				end
				timer.Create(e:EntIndex().."_JackpotMoney", 0.348 * 2, 0, function()
					if !IsValid(e) then return end
					e:StopParticleEmission()
					ParticleEffectAttach("wol_money_burst01", PATTACH_POINT_FOLLOW, e, 0)
				end)
				timer.Create(e:EntIndex().."_BonusLights", 0.348, 0, function()
					if !IsValid(e) then return end
					if e.PlayBounsLights then
						for _,v in ipairs(e.reels) do
							if !IsValid(v) then continue end
							if v:GetSkin() != 1 then
								v:SetSkin(1)
								v.targetSkin = 1
							else
								v:SetSkin(3)
								v.targetSkin = 3
							end
						end
					else
						timer.Remove(e:EntIndex().."_BonusLights")
						for _,v in ipairs(e.reels) do
							if !IsValid(v) then continue end
							v:SetSkin(1)
							v.targetSkin = 1
						end
					end
				end)
			end)
		else
			e.PlayBounsLights = false
			timer.Remove(e:EntIndex().."_BonusLights")
			timer.Remove(e:EntIndex().."_JackpotMoney")
			for _,v in ipairs(e.reels) do
				if !IsValid(v) then continue end
				v:SetSkin(1)
				v.targetSkin = 1
			end
			e.BonusSoundPlaying = false
			e.JackpotIsPlaying = false
		end
	end
end)